rigortype 0.3.1 → 0.3.2
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 +10 -10
- data/data/core_overlay/pathname.rbs +5 -0
- data/data/core_overlay/resolv.rbs +31 -0
- data/data/core_overlay/string_scanner.rbs +5 -0
- data/data/gem_overlay/activesupport/core_ext.rbs +10 -6
- data/data/vendored_gem_sigs/bundler/bundler.rbs +39 -27
- data/data/vendored_gem_sigs/cgi/cgi_extras.rbs +6 -0
- data/data/vendored_gem_sigs/prism/prism_supplement.rbs +7 -0
- data/data/vendored_gem_sigs/racc/racc.rbs +67 -0
- data/data/vendored_gem_sigs/rubygems/rubygems_extras.rbs +20 -9
- data/docs/manual/02-cli-reference.md +71 -11
- data/docs/manual/03-configuration.md +16 -1
- data/docs/manual/12-caching.md +17 -5
- data/docs/manual/15-type-protection-coverage.md +122 -1
- data/docs/manual/plugins/rigor-rbs-inline.md +22 -0
- data/lib/rigor/analysis/check_rules/rule_ids.rb +1 -0
- data/lib/rigor/analysis/check_rules.rb +45 -6
- data/lib/rigor/analysis/incremental_session.rb +156 -11
- data/lib/rigor/analysis/plugin_fact_fingerprint.rb +14 -0
- data/lib/rigor/analysis/run_cache_key.rb +17 -1
- data/lib/rigor/analysis/runner/buffer_pool_dispatcher.rb +201 -0
- data/lib/rigor/analysis/runner/diagnostic_aggregator.rb +28 -10
- data/lib/rigor/analysis/runner/pool_coordinator.rb +7 -10
- data/lib/rigor/analysis/runner/project_pre_passes.rb +3 -1
- data/lib/rigor/analysis/runner.rb +78 -7
- data/lib/rigor/bleeding_edge.rb +132 -7
- data/lib/rigor/cache/descriptor.rb +6 -1
- data/lib/rigor/cache/engine_source.rb +162 -0
- data/lib/rigor/cache/incremental_snapshot.rb +87 -18
- data/lib/rigor/cli/check_command.rb +49 -28
- data/lib/rigor/cli/coverage_command.rb +15 -2
- data/lib/rigor/cli/coverage_mutation.rb +242 -11
- data/lib/rigor/cli/fused_protection_renderer.rb +10 -0
- data/lib/rigor/cli/fused_protection_report.rb +12 -3
- data/lib/rigor/cli/mutation_fork_scan.rb +64 -0
- data/lib/rigor/cli/mutation_protection_renderer.rb +12 -0
- data/lib/rigor/cli/mutation_protection_report.rb +26 -5
- data/lib/rigor/cli/protection_renderer.rb +13 -0
- data/lib/rigor/cli/protection_report.rb +11 -3
- data/lib/rigor/cli/show_bleedingedge_command.rb +17 -4
- data/lib/rigor/cli/sig_gen_command.rb +5 -4
- data/lib/rigor/configuration.rb +45 -6
- data/lib/rigor/environment/bundle_sig_discovery.rb +2 -1
- data/lib/rigor/environment/rbs_coverage_report.rb +1 -1
- data/lib/rigor/environment/rbs_loader.rb +434 -75
- data/lib/rigor/environment.rb +28 -13
- data/lib/rigor/inference/expression_typer.rb +15 -0
- data/lib/rigor/inference/fork_map.rb +9 -0
- data/lib/rigor/inference/method_dispatcher/constant_folding.rb +50 -2
- data/lib/rigor/inference/method_dispatcher/data_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/member_shape_projection.rb +35 -1
- data/lib/rigor/inference/method_dispatcher/rbs_dispatch.rb +16 -0
- data/lib/rigor/inference/method_dispatcher/regexp_folding.rb +64 -5
- data/lib/rigor/inference/method_dispatcher/shape_dispatch.rb +137 -9
- data/lib/rigor/inference/method_dispatcher/struct_folding.rb +3 -2
- data/lib/rigor/inference/method_dispatcher/uri_folding.rb +124 -1
- data/lib/rigor/inference/mutation_widening.rb +30 -25
- data/lib/rigor/inference/narrowing.rb +3 -1
- data/lib/rigor/inference/optimistic_origin.rb +58 -0
- data/lib/rigor/inference/protection_scanner.rb +18 -2
- data/lib/rigor/inference/receiver_alias.rb +57 -0
- data/lib/rigor/inference/scope_indexer.rb +78 -27
- data/lib/rigor/inference/statement_evaluator.rb +40 -2
- data/lib/rigor/language_server/buffer_table.rb +22 -0
- data/lib/rigor/language_server/diagnostic_publisher.rb +203 -4
- data/lib/rigor/language_server/project_context.rb +45 -0
- data/lib/rigor/language_server/publish_batcher.rb +82 -0
- data/lib/rigor/language_server/server.rb +20 -1
- data/lib/rigor/language_server.rb +1 -0
- data/lib/rigor/plugin/source_rbs_synthesis_reporter.rb +9 -3
- data/lib/rigor/protection/closure_kill_oracle.rb +171 -0
- data/lib/rigor/protection/dependency_closure.rb +59 -0
- data/lib/rigor/protection/diagnostic_oracle.rb +12 -8
- data/lib/rigor/protection/discovery_seed.rb +116 -0
- data/lib/rigor/protection/kill_signature.rb +31 -0
- data/lib/rigor/protection/mutation_cache.rb +355 -0
- data/lib/rigor/protection/mutation_scanner.rb +55 -11
- data/lib/rigor/protection/mutator.rb +26 -4
- data/lib/rigor/runtime/jit.rb +63 -1
- data/lib/rigor/scope/discovery_index.rb +9 -0
- data/lib/rigor/scope.rb +52 -8
- data/lib/rigor/sig_gen/generator.rb +130 -31
- data/lib/rigor/sig_gen/layout_index.rb +6 -0
- data/lib/rigor/sig_gen/meta_class_shape.rb +84 -0
- data/lib/rigor/sig_gen/renderer.rb +20 -1
- data/lib/rigor/sig_gen/write_result.rb +6 -4
- data/lib/rigor/sig_gen/writer.rb +12 -0
- data/lib/rigor/sig_gen.rb +1 -0
- data/lib/rigor/version.rb +1 -1
- data/plugins/rigor-activesupport-core-ext/sig/active_support/core_ext.rbs +6 -6
- data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema/result_shape.rb +146 -0
- data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema/schema_scanner.rb +177 -12
- data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema.rb +74 -7
- data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation/contract_scanner.rb +257 -0
- data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation/params_shape.rb +69 -0
- data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation.rb +87 -11
- data/plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline.rb +34 -4
- data/sig/rigor/inference/void_origin.rbs +6 -3
- data/sig/rigor/scope.rbs +8 -0
- metadata +17 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 53ce9543e32229f3a80491f33886ac27cc0e1d3c0bb834536c703ab669188dd2
|
|
4
|
+
data.tar.gz: f9bb40e6e3a44a8bd362cee2b5f46a406d36391c5cf3053982950f4acae574df
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f233af3b211b096772e29ee29eda2ef7a7bca353e02f300c0f6ed36cbfb66deb73df709486896207f9459a0fbb5203c155ed257790c7d8122562780b1a532391
|
|
7
|
+
data.tar.gz: 21ed0e73b967f692d6df3a65a9cd6444b5b801b545cb82cb59e4cec8d0effdcec4e8f9b97ebd7a811a0ebe8a08366bdaabbb07df1338a59a939e5d855281b2be
|
data/README.md
CHANGED
|
@@ -108,7 +108,7 @@ Ready-made prompts — 日本語, 简体中文, 繁體中文, 한국어, Españo
|
|
|
108
108
|
Português, Français, Deutsch, Italiano, Tiếng Việt, ภาษาไทย,
|
|
109
109
|
Bahasa Indonesia, Polski, Українська, Русский, Română, Türkçe,
|
|
110
110
|
العربية, فارسی — are in
|
|
111
|
-
the [installation guide](https://rigor.typedduck.fail/
|
|
111
|
+
the [installation guide](https://rigor.typedduck.fail/manual/01-installation/#set-up-in-your-language).
|
|
112
112
|
|
|
113
113
|
**Manual install** — Rigor is a tool, not a library: install it
|
|
114
114
|
independently, **not** in your project's `Gemfile`. Install it
|
|
@@ -123,8 +123,8 @@ mise use -g ruby@4.0 gem:rigortype # or: gem install rigortype
|
|
|
123
123
|
|
|
124
124
|
The gem is named `rigortype` (the name `rigor` was taken on RubyGems);
|
|
125
125
|
the executable is `rigor`. `asdf`, dev containers, and CI templates are
|
|
126
|
-
in the [installation guide](https://rigor.typedduck.fail/
|
|
127
|
-
and [CI guide](https://rigor.typedduck.fail/
|
|
126
|
+
in the [installation guide](https://rigor.typedduck.fail/manual/01-installation/)
|
|
127
|
+
and [CI guide](https://rigor.typedduck.fail/manual/11-ci/).
|
|
128
128
|
|
|
129
129
|
### Daily commands
|
|
130
130
|
|
|
@@ -145,7 +145,7 @@ TeamCity).
|
|
|
145
145
|
1. **Types are facts, not wishes.** Hand-written annotations drift the
|
|
146
146
|
moment they are written. Rigor infers from the code itself — every
|
|
147
147
|
type is derived from what your source actually produces. When you do
|
|
148
|
-
want RBS in `sig/`, [`rigor sig-gen`](https://rigor.typedduck.fail/
|
|
148
|
+
want RBS in `sig/`, [`rigor sig-gen`](https://rigor.typedduck.fail/adr/14-rbs-sig-generation/)
|
|
149
149
|
emits it from inference results so the written form starts in sync
|
|
150
150
|
with reality.
|
|
151
151
|
2. **A false positive is the worst bug.** Your program works; a
|
|
@@ -161,7 +161,7 @@ TeamCity).
|
|
|
161
161
|
literal values, integer ranges, refinements like
|
|
162
162
|
`non-empty-string`, and per-position tuple / hash shapes — and
|
|
163
163
|
exposes a plugin API plus a
|
|
164
|
-
[macro / DSL expansion substrate](https://rigor.typedduck.fail/
|
|
164
|
+
[macro / DSL expansion substrate](https://rigor.typedduck.fail/adr/16-macro-expansion/)
|
|
165
165
|
so Rails-shape DSLs become first-class type sources.
|
|
166
166
|
|
|
167
167
|
## Works with your stack
|
|
@@ -202,10 +202,10 @@ interop, so adopting Rigor is strictly additive. When you want to
|
|
|
202
202
|
in `sig/` files tighten types while staying a no-op for ordinary RBS
|
|
203
203
|
tools.
|
|
204
204
|
|
|
205
|
-
The twelve-chapter [handbook](https://rigor.typedduck.fail/
|
|
205
|
+
The twelve-chapter [handbook](https://rigor.typedduck.fail/handbook/)
|
|
206
206
|
walks the whole type model; the
|
|
207
|
-
[type specification](https://rigor.typedduck.fail/
|
|
208
|
-
and [user manual](https://rigor.typedduck.fail/
|
|
207
|
+
[type specification](https://rigor.typedduck.fail/type-specification/)
|
|
208
|
+
and [user manual](https://rigor.typedduck.fail/manual/) are
|
|
209
209
|
the reference companions.
|
|
210
210
|
|
|
211
211
|
**Stuck on Rigor — or just curious how it works? Ask your agent in
|
|
@@ -231,7 +231,7 @@ rigor docs --list # list every bundled page
|
|
|
231
231
|
|
|
232
232
|
## Status
|
|
233
233
|
|
|
234
|
-
Current release: **`v0.3.
|
|
234
|
+
Current release: **`v0.3.2`** (2026-08-08) — on the
|
|
235
235
|
`0.3.x` line, continuing the evaluation era opened by `v0.2.0`, the first
|
|
236
236
|
publicly-announced (general / evaluation) release. The line publishes
|
|
237
237
|
an enumerated [compatibility surface](docs/compatibility.md) as a
|
|
@@ -241,7 +241,7 @@ Mastodon, Redmine, and GitLab FOSS, and the deliberately conservative
|
|
|
241
241
|
rule catalogue grows only as fast as the zero-false-positive bar
|
|
242
242
|
allows. Release history: [`CHANGELOG.md`](CHANGELOG.md) ·
|
|
243
243
|
forward-looking commitments:
|
|
244
|
-
[Roadmap](https://
|
|
244
|
+
[Roadmap](https://github.com/rigortype/rigor/milestones).
|
|
245
245
|
|
|
246
246
|
## Contributing
|
|
247
247
|
|
|
@@ -19,6 +19,11 @@
|
|
|
19
19
|
#
|
|
20
20
|
# The overlay widens `dir` to `String | Pathname`, matching the runtime
|
|
21
21
|
# delegation and the `File.expand_path` `path` alias used elsewhere in RBS.
|
|
22
|
+
#
|
|
23
|
+
# The `| ...` continuation is safe with no library loaded — unlike the
|
|
24
|
+
# `RbsLoader::LIBRARY_SUPPLEMENT_CORE_OVERLAYS` files, its base declaration
|
|
25
|
+
# lives in rbs's `core/pathname.rbs` on every supported rbs release
|
|
26
|
+
# (3.10 / 4.0 / 4.1), not in the `pathname` stdlib library.
|
|
22
27
|
class Pathname
|
|
23
28
|
def expand_path: (?String | Pathname dir) -> Pathname
|
|
24
29
|
| ...
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Rigor core overlay — supplemental core signatures.
|
|
2
|
+
#
|
|
3
|
+
# --- Resolv#initialize ---
|
|
4
|
+
#
|
|
5
|
+
# `rbs` before 4.1 declares `Resolv#initialize` as only:
|
|
6
|
+
#
|
|
7
|
+
# def initialize: (?Resolv::Hosts | Resolv::DNS resolvers) -> untyped
|
|
8
|
+
#
|
|
9
|
+
# But `Resolv.new` takes an *array* of resolvers — the runtime default is
|
|
10
|
+
# `[Hosts.new, DNS.new]`, and `each_address` iterates the argument — so the
|
|
11
|
+
# documented, idiomatic call passes an Array:
|
|
12
|
+
#
|
|
13
|
+
# Resolv.new([Resolv::Hosts.new, Resolv::DNS.new(nameserver: ...)])
|
|
14
|
+
#
|
|
15
|
+
# Against the pre-4.1 signature every overload rejects that Array and
|
|
16
|
+
# `call.argument-type-mismatch` false-fires (measured on Mastodon's
|
|
17
|
+
# `app/lib/request.rb`).
|
|
18
|
+
#
|
|
19
|
+
# `rbs` 4.1.0 fixed the signature upstream (ruby/rbs#2960); the overlay
|
|
20
|
+
# backports that overload for the older releases the gemspec still supports
|
|
21
|
+
# (`>= 3.0, < 5.0`). On 4.1 the appended overload duplicates the upstream
|
|
22
|
+
# one, which costs nothing. Drop this file when the rbs floor reaches 4.1.
|
|
23
|
+
#
|
|
24
|
+
# Loaded ONLY when the `resolv` library resolves
|
|
25
|
+
# (`RbsLoader::LIBRARY_SUPPLEMENT_CORE_OVERLAYS`): the `| ...` overload
|
|
26
|
+
# continuation is invalid without the base declaration, and the resulting
|
|
27
|
+
# `InvalidOverloadMethodError` would take the whole class down.
|
|
28
|
+
class Resolv
|
|
29
|
+
def initialize: (?(Array[Resolv::Hosts | Resolv::DNS] | Hash[Symbol, untyped])? resolvers, ?use_ipv6: bool?) -> untyped
|
|
30
|
+
| ...
|
|
31
|
+
end
|
|
@@ -23,6 +23,11 @@
|
|
|
23
23
|
# earns its keep for a consumer resolving an older `rbs` inside the
|
|
24
24
|
# gemspec's `>= 3.0, < 5.0` range. It stays until that floor moves;
|
|
25
25
|
# reopening with an identical overload costs nothing on 4.1.
|
|
26
|
+
#
|
|
27
|
+
# Loaded ONLY when the `strscan` library resolves
|
|
28
|
+
# (`RbsLoader::LIBRARY_SUPPLEMENT_CORE_OVERLAYS`): the `| ...` overload
|
|
29
|
+
# continuation is invalid without the base declaration, and the resulting
|
|
30
|
+
# `InvalidOverloadMethodError` would take the whole class down.
|
|
26
31
|
class StringScanner
|
|
27
32
|
def []: (Integer | String | Symbol) -> String?
|
|
28
33
|
| ...
|
|
@@ -245,10 +245,10 @@ class Time
|
|
|
245
245
|
def self.zone: () -> untyped # ActiveSupport::TimeZone | nil
|
|
246
246
|
def self.zone=: (String | Symbol | untyped) -> untyped
|
|
247
247
|
|
|
248
|
-
# `core_ext/time/conversions` —
|
|
249
|
-
# `time`, which
|
|
250
|
-
|
|
251
|
-
|
|
248
|
+
# `core_ext/time/conversions` — nothing to declare. `Time.parse`, `Time.httpdate` and `Time.iso8601`
|
|
249
|
+
# all come from stdlib `time`, which rbs types; ActiveSupport only re-opens them. Declaring them
|
|
250
|
+
# here raised `RBS::DuplicatedMethodDefinitionError` and collapsed the whole `Time` definition to
|
|
251
|
+
# `Dynamic[top]`.
|
|
252
252
|
|
|
253
253
|
# `core_ext/time/calculations`
|
|
254
254
|
def yesterday: () -> Time
|
|
@@ -278,7 +278,10 @@ class Time
|
|
|
278
278
|
def midday: () -> Time
|
|
279
279
|
def midnight: () -> Time
|
|
280
280
|
def noon: () -> Time
|
|
281
|
-
|
|
281
|
+
# NOTE: `Time#utc?` is NOT declared here — it is Ruby core, already typed by rbs's `core/time.rbs`.
|
|
282
|
+
# Re-declaring it raised `RBS::DuplicatedMethodDefinitionError` and took the WHOLE `Time` definition
|
|
283
|
+
# down with it (every `Time` call degraded to `Dynamic[top]`). This overlay only ADDS what
|
|
284
|
+
# ActiveSupport adds.
|
|
282
285
|
def acts_like_time?: () -> true
|
|
283
286
|
end
|
|
284
287
|
|
|
@@ -457,7 +460,8 @@ end
|
|
|
457
460
|
|
|
458
461
|
class DateTime
|
|
459
462
|
def utc: () -> Time
|
|
460
|
-
|
|
463
|
+
# NOTE: `DateTime#to_time` is NOT declared here — stdlib `date` already types it, and re-declaring it
|
|
464
|
+
# collapsed the whole `DateTime` definition (see the `Time#utc?` note above).
|
|
461
465
|
def in_time_zone: (?String | Symbol zone) -> untyped
|
|
462
466
|
def yesterday: () -> DateTime
|
|
463
467
|
def tomorrow: () -> DateTime
|
|
@@ -2,14 +2,12 @@
|
|
|
2
2
|
# Rigor-side vendored RBS stub for the `bundler` gem.
|
|
3
3
|
#
|
|
4
4
|
# The `bundler` gem does not ship its own `sig/` and is not
|
|
5
|
-
# covered by `ruby/gem_rbs_collection`. The
|
|
6
|
-
# `
|
|
7
|
-
#
|
|
8
|
-
# `
|
|
9
|
-
#
|
|
10
|
-
#
|
|
11
|
-
# so most projects analyse bundler-using code with NO `Bundler`
|
|
12
|
-
# RBS in scope.
|
|
5
|
+
# covered by `ruby/gem_rbs_collection`. The rbs gem's own
|
|
6
|
+
# `sig/shims/bundler.rbs` carries a tiny subset (`LockfileParser`,
|
|
7
|
+
# `LazySpecification`, `Dependency`, `Definition`,
|
|
8
|
+
# `default_lockfile`, `definition`, `Source::Gemspec`) — enough to
|
|
9
|
+
# type rbs's own use of bundler, not enough to analyse a project
|
|
10
|
+
# that uses it.
|
|
13
11
|
#
|
|
14
12
|
# This stub covers the Bundler module's top-25 singleton methods
|
|
15
13
|
# surfaced by the `references/ruby/lib` survey
|
|
@@ -21,13 +19,23 @@
|
|
|
21
19
|
# silence `call.undefined-method` rather than infer precise
|
|
22
20
|
# returns.
|
|
23
21
|
#
|
|
24
|
-
#
|
|
25
|
-
# `
|
|
26
|
-
#
|
|
27
|
-
#
|
|
28
|
-
#
|
|
29
|
-
# `
|
|
30
|
-
#
|
|
22
|
+
# The `rbs` gem's own `sig/shims/bundler.rbs` IS always in scope:
|
|
23
|
+
# `rbs` sits in `Environment::DEFAULT_LIBRARIES`, so its `sig/`
|
|
24
|
+
# tree — shims included — loads on every run. This file therefore
|
|
25
|
+
# declares only what the shim does NOT, and never re-declares a
|
|
26
|
+
# shim method: a duplicate raises
|
|
27
|
+
# `RBS::DuplicatedMethodDefinitionError` inside
|
|
28
|
+
# `RBS::DefinitionBuilder` and collapses the ENTIRE class to
|
|
29
|
+
# `Dynamic[top]` (issue #299). Where the shim's type is weaker
|
|
30
|
+
# than Rigor's would have been, the shim still wins: an RBS
|
|
31
|
+
# overload continuation (`| ...`) would append rather than
|
|
32
|
+
# collide, but it raises `InvalidOverloadMethodError` when the
|
|
33
|
+
# base declaration is absent, which breaks every environment
|
|
34
|
+
# built without the `rbs` library. Those spots are marked below.
|
|
35
|
+
#
|
|
36
|
+
# Keep this file and `sig/shims/bundler.rbs` in sync on an `rbs`
|
|
37
|
+
# bump — `spec/rigor/environment/bundled_rbs_definition_build_spec.rb`
|
|
38
|
+
# fails the suite if a new collision reappears.
|
|
31
39
|
#
|
|
32
40
|
module Bundler
|
|
33
41
|
# `Bundler.<name>` — accessors / module-level entry points.
|
|
@@ -46,7 +54,13 @@ module Bundler
|
|
|
46
54
|
def self.require: (*untyped groups) -> untyped
|
|
47
55
|
def self.load: () -> untyped
|
|
48
56
|
def self.environment: () -> untyped
|
|
49
|
-
|
|
57
|
+
# `self.definition` — declared by `sig/shims/bundler.rbs`. Note that the shim types it `() ->
|
|
58
|
+
# Definition` while the real `Bundler.definition(unlock = nil, lockfile = default_lockfile)` takes
|
|
59
|
+
# two optional arguments; an `| ...` overload continuation here would restore that arity, but a
|
|
60
|
+
# continuation with no base declaration raises `RBS::InvalidOverloadMethodError` — so any
|
|
61
|
+
# environment built WITHOUT the `rbs` library would lose the whole `Bundler` module to
|
|
62
|
+
# `Dynamic[top]`. The narrower arity is the cheaper of the two failure modes; the fix belongs
|
|
63
|
+
# upstream in the shim.
|
|
50
64
|
def self.frozen_bundle?: () -> bool
|
|
51
65
|
def self.locked_gems: () -> untyped
|
|
52
66
|
def self.ruby_scope: () -> String
|
|
@@ -78,7 +92,7 @@ module Bundler
|
|
|
78
92
|
def self.local_platform: () -> untyped
|
|
79
93
|
def self.generic_local_platform: () -> untyped
|
|
80
94
|
def self.default_gemfile: () -> Pathname
|
|
81
|
-
|
|
95
|
+
# `self.default_lockfile` — declared by `sig/shims/bundler.rbs` with the same type.
|
|
82
96
|
def self.default_bundle_dir: () -> Pathname?
|
|
83
97
|
def self.system_bindir: () -> String?
|
|
84
98
|
def self.preferred_gemfile_name: () -> String
|
|
@@ -104,10 +118,9 @@ module Bundler
|
|
|
104
118
|
|
|
105
119
|
def initialize: (*untyped) -> void
|
|
106
120
|
def gemfiles: () -> Array[Pathname]
|
|
107
|
-
|
|
121
|
+
# `#lockfile`, `#locked_gems`, `#dependencies` — declared by `sig/shims/bundler.rbs` with the
|
|
122
|
+
# same types.
|
|
108
123
|
def lockfile=: (untyped) -> untyped
|
|
109
|
-
def locked_gems: () -> LockfileParser
|
|
110
|
-
def dependencies: () -> Array[Dependency]
|
|
111
124
|
def current_dependencies: () -> Array[Dependency]
|
|
112
125
|
def requested_dependencies: () -> Array[Dependency]
|
|
113
126
|
def dependencies_for: (untyped groups) -> Array[Dependency]
|
|
@@ -134,8 +147,7 @@ module Bundler
|
|
|
134
147
|
end
|
|
135
148
|
|
|
136
149
|
class LockfileParser
|
|
137
|
-
|
|
138
|
-
def specs: () -> Array[LazySpecification]
|
|
150
|
+
# `#initialize`, `#specs` — declared by `sig/shims/bundler.rbs` with the same types.
|
|
139
151
|
def platforms: () -> Array[untyped]
|
|
140
152
|
def sources: () -> Array[untyped]
|
|
141
153
|
def dependencies: () -> Array[Dependency]
|
|
@@ -144,16 +156,16 @@ module Bundler
|
|
|
144
156
|
end
|
|
145
157
|
|
|
146
158
|
class LazySpecification
|
|
147
|
-
|
|
148
|
-
|
|
159
|
+
# `#name`, `#version`, `#dependencies` — declared by `sig/shims/bundler.rbs`. The shim types
|
|
160
|
+
# `#version` as `() -> String` where bundler returns a `Gem::Version`; see the note on
|
|
161
|
+
# `Bundler.definition` above for why that is left alone rather than corrected with an `| ...`
|
|
162
|
+
# overload continuation.
|
|
149
163
|
def platform: () -> untyped
|
|
150
|
-
def dependencies: () -> Array[Gem::Dependency]
|
|
151
164
|
def source: () -> untyped
|
|
152
165
|
end
|
|
153
166
|
|
|
154
167
|
class Dependency < Gem::Dependency
|
|
155
|
-
|
|
156
|
-
attr_reader source: untyped
|
|
168
|
+
# `#autorequire`, `#source` — declared by `sig/shims/bundler.rbs` with the same types.
|
|
157
169
|
attr_reader groups: Array[Symbol]
|
|
158
170
|
attr_reader platforms: Array[Symbol]
|
|
159
171
|
end
|
|
@@ -29,6 +29,12 @@
|
|
|
29
29
|
# `include CGI::Util` + `extend CGI::Util`; adding a sibling
|
|
30
30
|
# `include CGI::QueryExtension` is purely additive.
|
|
31
31
|
#
|
|
32
|
+
# Loaded ONLY when the `cgi` stdlib library resolves
|
|
33
|
+
# (`RbsLoader::LIBRARY_SUPPLEMENT_VENDORED_DIRS`): without it the
|
|
34
|
+
# mixin target does not exist, `RBS::DefinitionBuilder` raises
|
|
35
|
+
# `NoMixinFoundError`, and the whole `CGI` class silently degrades
|
|
36
|
+
# to `Dynamic[top]`.
|
|
37
|
+
#
|
|
32
38
|
class CGI
|
|
33
39
|
include CGI::QueryExtension
|
|
34
40
|
end
|
|
@@ -21,6 +21,13 @@
|
|
|
21
21
|
# — bound as singleton methods by the C extension; the
|
|
22
22
|
# gem's RBS only declares the matching instance methods.
|
|
23
23
|
#
|
|
24
|
+
# Loaded ONLY when the `prism` library resolves
|
|
25
|
+
# (`RbsLoader::LIBRARY_SUPPLEMENT_VENDORED_DIRS`): the
|
|
26
|
+
# `ParseResult < Result` re-opening names a superclass only the
|
|
27
|
+
# gem's own RBS declares, so without it `RBS::DefinitionBuilder`
|
|
28
|
+
# raises `NoSuperclassFoundError` and the whole class silently
|
|
29
|
+
# degrades to `Dynamic[top]`.
|
|
30
|
+
#
|
|
24
31
|
module Prism
|
|
25
32
|
class ParseResult < Result
|
|
26
33
|
# Walk the parse result's tree, attaching every comment to
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Rigor-side vendored RBS stub for the `racc` gem's runtime.
|
|
3
|
+
#
|
|
4
|
+
# Vendored for ONE structural reason: `data/vendored_gem_sigs/nokogiri/nokogiri.rbs` declares
|
|
5
|
+
# `class Nokogiri::CSS::Parser < Racc::Parser`, and `RBS::DefinitionBuilder` raises
|
|
6
|
+
# `RBS::NoSuperclassFoundError` when a declared superclass has no declaration anywhere in the
|
|
7
|
+
# environment — which took the whole `Nokogiri::CSS::Parser` definition down to `Dynamic[top]`
|
|
8
|
+
# (issue #299). Dropping the superclass from the nokogiri sig would have hidden the inheritance
|
|
9
|
+
# instead of typing it, and `Racc::Parser` is a real, small, stable class, so it is declared here.
|
|
10
|
+
#
|
|
11
|
+
# Scope is the documented runtime surface a racc-generated parser inherits, plus `Racc::ParseError`
|
|
12
|
+
# (which `Nokogiri::CSS::SyntaxError` and every generated parser raise). The `_racc_*` methods are
|
|
13
|
+
# private implementation detail of the generated parse loop and are deliberately NOT declared —
|
|
14
|
+
# nothing outside racc itself calls them.
|
|
15
|
+
#
|
|
16
|
+
# Returns are `untyped` wherever the value is a grammar-defined semantic value: racc has no way to
|
|
17
|
+
# know what a generated parser's actions produce, and guessing would cost false positives.
|
|
18
|
+
#
|
|
19
|
+
module Racc
|
|
20
|
+
# Raised by a generated parser on an unrecoverable syntax error.
|
|
21
|
+
class ParseError < StandardError
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# The runtime base class every racc-generated parser inherits from.
|
|
25
|
+
class Parser
|
|
26
|
+
# Runs the parse loop, pulling tokens from the subclass's `#next_token`. Returns the grammar's
|
|
27
|
+
# start-rule value.
|
|
28
|
+
def do_parse: () -> untyped
|
|
29
|
+
|
|
30
|
+
# Token source: a generated parser's user code overrides this to return `[token_symbol, value]`,
|
|
31
|
+
# or `nil` / `[false, ...]` at end of input.
|
|
32
|
+
def next_token: () -> untyped
|
|
33
|
+
|
|
34
|
+
# Runs the parse loop pulling tokens by calling `recv.__send__(mid)` instead of `#next_token`.
|
|
35
|
+
def yyparse: (untyped recv, Symbol | String mid) -> untyped
|
|
36
|
+
|
|
37
|
+
# Error hook: called with the offending token id, its value, and the value stack. The default
|
|
38
|
+
# implementation raises `Racc::ParseError`; user code overrides it to report and recover.
|
|
39
|
+
def on_error: (untyped error_token_id, untyped error_value, untyped value_stack) -> void
|
|
40
|
+
|
|
41
|
+
# Explicitly signals a syntax error from inside a parser action.
|
|
42
|
+
def yyerror: () -> void
|
|
43
|
+
|
|
44
|
+
# Accepts the input from inside a parser action, ending the parse.
|
|
45
|
+
def yyaccept: () -> void
|
|
46
|
+
|
|
47
|
+
# Clears the error state after `#on_error`, resuming normal parsing.
|
|
48
|
+
def yyerrok: () -> void
|
|
49
|
+
|
|
50
|
+
# Human-readable name for a token id, or `nil` when the id is unknown.
|
|
51
|
+
def token_to_str: (untyped t) -> String?
|
|
52
|
+
|
|
53
|
+
# Debug-trace hooks. Enabled by a generated parser built with racc's `--debug`; harmless no-ops
|
|
54
|
+
# otherwise.
|
|
55
|
+
def racc_read_token: (untyped t, untyped tok, untyped val) -> void
|
|
56
|
+
def racc_shift: (untyped tok, untyped tstack, untyped vstack) -> void
|
|
57
|
+
def racc_reduce: (untyped toks, untyped sim, untyped tstack, untyped vstack) -> void
|
|
58
|
+
def racc_accept: () -> void
|
|
59
|
+
def racc_e_pop: (untyped state, untyped tstack, untyped vstack) -> void
|
|
60
|
+
def racc_next_state: (untyped curstate, untyped state) -> void
|
|
61
|
+
def racc_print_stacks: (untyped t, untyped v) -> void
|
|
62
|
+
def racc_print_states: (untyped s) -> void
|
|
63
|
+
def racc_token2str: (untyped tok) -> String
|
|
64
|
+
|
|
65
|
+
def self.racc_runtime_type: () -> String
|
|
66
|
+
end
|
|
67
|
+
end
|
|
@@ -8,6 +8,17 @@
|
|
|
8
8
|
# the upstream RBS already covers, so the loader does not raise
|
|
9
9
|
# `RBS::DuplicatedDeclarationError`.
|
|
10
10
|
#
|
|
11
|
+
# "Upstream RBS" here means BOTH `core/rubygems/*.rbs` and the
|
|
12
|
+
# `rbs` gem's `sig/shims/rubygems.rbs`: `rbs` is in
|
|
13
|
+
# `Environment::DEFAULT_LIBRARIES`, so its whole `sig/` tree —
|
|
14
|
+
# shims included — is in scope on every run. A duplicate against
|
|
15
|
+
# either raises `RBS::DuplicatedMethodDefinitionError` inside
|
|
16
|
+
# `RBS::DefinitionBuilder` and collapses the ENTIRE class to
|
|
17
|
+
# `Dynamic[top]` (issue #299), so a shim-declared reader is left
|
|
18
|
+
# to the shim and only the writer half is declared here.
|
|
19
|
+
# `spec/rigor/environment/bundled_rbs_definition_build_spec.rb`
|
|
20
|
+
# fails the suite if a new collision reappears on an `rbs` bump.
|
|
21
|
+
#
|
|
11
22
|
# Driven by the `references/ruby/lib` survey
|
|
12
23
|
# (`docs/CURRENT_WORK.md` § "Queued engine items") which
|
|
13
24
|
# clusters `undefined-method` on Gem-side selectors most-touched
|
|
@@ -62,7 +73,7 @@ class Gem::Platform
|
|
|
62
73
|
def match_spec?: (untyped) -> bool
|
|
63
74
|
def match_gem?: (untyped, untyped) -> bool
|
|
64
75
|
|
|
65
|
-
def self.local: () -> Platform
|
|
76
|
+
def self.local: () -> Gem::Platform
|
|
66
77
|
def self.match_spec?: (untyped) -> bool
|
|
67
78
|
def self.match_gem?: (untyped, untyped) -> bool
|
|
68
79
|
def self.installable?: (untyped) -> bool
|
|
@@ -75,7 +86,9 @@ class Gem::Dependency
|
|
|
75
86
|
# permissive splat keeps the canonical and the
|
|
76
87
|
# `(name, requirements, type)` invocation forms both silent.
|
|
77
88
|
def initialize: (*untyped) -> void
|
|
78
|
-
|
|
89
|
+
# `#name`'s READER is declared by `sig/shims/rubygems.rbs` (`() -> String`); only the writer is
|
|
90
|
+
# ours, so this is a `def name=` rather than the `attr_accessor` the other members use.
|
|
91
|
+
def name=: (String) -> String
|
|
79
92
|
attr_accessor requirement: Gem::Requirement
|
|
80
93
|
attr_accessor type: Symbol
|
|
81
94
|
attr_accessor prerelease: bool
|
|
@@ -111,7 +124,9 @@ class Gem::Specification
|
|
|
111
124
|
def required_ruby_version: () -> Gem::Requirement
|
|
112
125
|
def require_paths: () -> Array[String]
|
|
113
126
|
attr_accessor name: String
|
|
114
|
-
|
|
127
|
+
# `#version`'s READER is declared by `sig/shims/rubygems.rbs` (`attr_reader version (): Version`);
|
|
128
|
+
# only the writer is ours.
|
|
129
|
+
def version=: (Gem::Version) -> Gem::Version
|
|
115
130
|
attr_accessor full_gem_path: String
|
|
116
131
|
attr_accessor loaded_from: String?
|
|
117
132
|
attr_accessor post_install_message: String?
|
|
@@ -131,7 +146,7 @@ end
|
|
|
131
146
|
|
|
132
147
|
class Gem::Requirement
|
|
133
148
|
def requirements: () -> Array[untyped]
|
|
134
|
-
|
|
149
|
+
# `.create` — declared by `core/rubygems/requirement.rbs`, and more precisely than this file did.
|
|
135
150
|
end
|
|
136
151
|
|
|
137
152
|
class Gem::ConfigFile
|
|
@@ -172,7 +187,7 @@ class Gem::SourceList
|
|
|
172
187
|
def include?: (untyped) -> bool
|
|
173
188
|
def each: () { (untyped) -> untyped } -> void
|
|
174
189
|
def to_a: () -> Array[untyped]
|
|
175
|
-
def from: (untyped) -> SourceList
|
|
190
|
+
def from: (untyped) -> Gem::SourceList
|
|
176
191
|
end
|
|
177
192
|
|
|
178
193
|
class Gem::RequestSet
|
|
@@ -217,10 +232,6 @@ class Gem::Installer
|
|
|
217
232
|
def initialize: (*untyped) -> void
|
|
218
233
|
end
|
|
219
234
|
|
|
220
|
-
class Gem::DependencyInstaller
|
|
221
|
-
def initialize: (*untyped) -> void
|
|
222
|
-
end
|
|
223
|
-
|
|
224
235
|
class Gem::MissingSpecError < StandardError
|
|
225
236
|
def initialize: (*untyped) -> void
|
|
226
237
|
end
|
|
@@ -48,11 +48,38 @@ the `paths:` list from the configuration file.
|
|
|
48
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
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. Inspect it with [`rigor show-bleedingedge`](#rigor-show-bleedingedge). |
|
|
50
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. |
|
|
51
|
+
| `--tmp-file=PATH --instead-of=PATH` | Editor mode: analyse `PATH` using the buffer in `--tmp-file`. Both required together. Alone, only the buffer's own file produces diagnostics; add `--incremental` for whole-project scope (see below). |
|
|
52
52
|
|
|
53
53
|
Exit `0` when no error-severity diagnostics remain, `1` when
|
|
54
54
|
any are reported, `64` on a usage error.
|
|
55
55
|
|
|
56
|
+
### Editor mode scope
|
|
57
|
+
|
|
58
|
+
`--tmp-file` / `--instead-of` on their own analyse **only** the
|
|
59
|
+
buffer's file: fast, and blind to what the unsaved edit does to the
|
|
60
|
+
rest of the project.
|
|
61
|
+
|
|
62
|
+
Adding `--incremental` analyses the **whole project with the buffer
|
|
63
|
+
substituted** — the edited file and the files that depend on it are
|
|
64
|
+
re-analysed, everything else is served from the incremental snapshot.
|
|
65
|
+
An unsaved change to a method's return type therefore surfaces in its
|
|
66
|
+
callers, not just in the file being edited.
|
|
67
|
+
|
|
68
|
+
Two things to know:
|
|
69
|
+
|
|
70
|
+
- It needs a snapshot to reuse. Run `rigor check --incremental` once
|
|
71
|
+
(it is also what a normal terminal check should use) and every later
|
|
72
|
+
editor invocation gets whole-project scope. Without one, Rigor says
|
|
73
|
+
so on stderr and analyses the buffer alone.
|
|
74
|
+
- An editor-mode run never writes the snapshot — the buffer's bytes
|
|
75
|
+
exist only in your editor, and recording them would make the next
|
|
76
|
+
ordinary run believe it had already analysed a file in a state it
|
|
77
|
+
was never in.
|
|
78
|
+
|
|
79
|
+
`--verify-incremental` refuses a buffer: it compares against a full
|
|
80
|
+
analysis of the files on disk, which a buffer contradicts by
|
|
81
|
+
construction.
|
|
82
|
+
|
|
56
83
|
## `rigor init`
|
|
57
84
|
|
|
58
85
|
Write a starter configuration file.
|
|
@@ -333,7 +360,10 @@ the effectiveness ratio and `--format=json` carries `mode`,
|
|
|
333
360
|
`killed`, `survived`, `effectiveness_ratio`, per-file rows, and
|
|
334
361
|
`add_a_type_here`. It is the truth tier behind the static
|
|
335
362
|
`--protection` proxy, at the cost of many analyses — an opt-in CI
|
|
336
|
-
deep-dive, not an interactive check.
|
|
363
|
+
deep-dive, not an interactive check. `--workers=N` fork-parallelizes
|
|
364
|
+
this tier too (the whole-project pre-pass is paid once on the parent
|
|
365
|
+
and the per-file measurement is spread across workers), with the
|
|
366
|
+
same precedence chain and the same byte-identical output.
|
|
337
367
|
|
|
338
368
|
```sh
|
|
339
369
|
rigor coverage --protection --mutation [paths]
|
|
@@ -352,7 +382,10 @@ cost is proportional to the protection hole. `--format=json`
|
|
|
352
382
|
carries `mode` (`protection-fused`), `type_killed`,
|
|
353
383
|
`test_killed`, `unprotected`, `protected_ratio`, per-file rows,
|
|
354
384
|
and `add_protection_here`; `--threshold` gates on the fused
|
|
355
|
-
ratio.
|
|
385
|
+
ratio. This tier is always sequential — the suite hook shells out
|
|
386
|
+
to your test runner, and concurrent runs would race over one
|
|
387
|
+
working tree — so `--workers` does not apply and an explicit one
|
|
388
|
+
is reported as ignored on stderr.
|
|
356
389
|
|
|
357
390
|
`--test-command=CMD` is the runner hook (default
|
|
358
391
|
`bundle exec rake`). The suite must pass on clean code first, or
|
|
@@ -378,6 +411,18 @@ to a deterministic sample of `N` mutations per file, bounding the
|
|
|
378
411
|
cost on large files. Per-file ratios then become estimates, noted
|
|
379
412
|
on stderr so `--format=json` stdout stays clean.
|
|
380
413
|
|
|
414
|
+
A re-run is served from a per-file measurement cache while
|
|
415
|
+
nothing that could change a file's number has moved: the file
|
|
416
|
+
itself, any file it was recorded as reading from, the resolved
|
|
417
|
+
configuration, `sig/`, the gem set, the engine version, `--limit`
|
|
418
|
+
/ `--seed`, and the adopted bleeding-edge features. It reads the
|
|
419
|
+
cross-file edges a `rigor check --incremental` run records, so
|
|
420
|
+
warm one once per project; without a usable snapshot every file
|
|
421
|
+
is measured, never silently served. `--no-cache` measures
|
|
422
|
+
everything from scratch. A one-line stderr report says which of
|
|
423
|
+
those happened — see
|
|
424
|
+
[Type-protection coverage](15-type-protection-coverage.md).
|
|
425
|
+
|
|
381
426
|
```sh
|
|
382
427
|
rigor coverage --protection --mutation --with-tests \
|
|
383
428
|
--test-command "bundle exec rspec" --include-dynamic [paths]
|
|
@@ -578,7 +623,7 @@ pages from the installed gem with no HTTP request.
|
|
|
578
623
|
## `rigor show-bleedingedge`
|
|
579
624
|
|
|
580
625
|
Print the **bleeding-edge overlay** — the Rigor-maintained set of
|
|
581
|
-
the next major's queued
|
|
626
|
+
the next major's queued changes ([ADR-50](../adr/50-release-engineering-and-stability-strategy.md)
|
|
582
627
|
§ WD2) — and report which of them the project's
|
|
583
628
|
[`bleeding_edge:`](03-configuration.md) configuration adopts. Read-only:
|
|
584
629
|
it loads `.rigor.yml` to resolve the active selection but runs no
|
|
@@ -593,16 +638,31 @@ rigor show-bleedingedge [--config PATH] [--format text|json]
|
|
|
593
638
|
| `--config PATH` | Use this `.rigor.yml` instead of auto-discovery. |
|
|
594
639
|
| `--format text\|json` | Output format. Default `text`. |
|
|
595
640
|
|
|
596
|
-
Each queued feature appears with its stable id,
|
|
597
|
-
and whether your configuration adopts it.
|
|
598
|
-
|
|
599
|
-
|
|
641
|
+
Each queued feature appears with its stable id, its **kind** — `severity`
|
|
642
|
+
or `behaviour` — and whether your configuration adopts it. A `severity`
|
|
643
|
+
feature also prints the rule → severity diff it imposes; a `behaviour`
|
|
644
|
+
feature changes a measurement, an algorithm, or a default without moving
|
|
645
|
+
any rule's severity, so it has no such diff and its summary is the whole
|
|
646
|
+
description. See [`docs/compatibility.md`](../compatibility.md) for how
|
|
647
|
+
bleeding-edge fits the stability model.
|
|
600
648
|
|
|
601
649
|
Queued today:
|
|
602
650
|
|
|
603
|
-
| Feature id | What it changes |
|
|
604
|
-
| --- | --- |
|
|
605
|
-
| `reject-unparseable-signatures` | An unparseable `.rbs` under `signature_paths:` **fails the run** (`rbs.coverage.quarantined-signature` → `error`) instead of being skipped with a warning. |
|
|
651
|
+
| Feature id | Kind | What it changes |
|
|
652
|
+
| --- | --- | --- |
|
|
653
|
+
| `reject-unparseable-signatures` | severity | An unparseable `.rbs` under `signature_paths:` **fails the run** (`rbs.coverage.quarantined-signature` → `error`) instead of being skipped with a warning. |
|
|
654
|
+
| `use-of-void-value` | severity | Using a value recovered from an author-declared `-> void` return in value context is reported as `static.value-use.void` (`warning`). |
|
|
655
|
+
| `discovery-seeded-mutation-sites` | behaviour | [`rigor coverage --protection --mutation`](15-type-protection-coverage.md) measures against the same cross-file project discovery Tier 1 already uses — both when picking the sites and when deciding whether a breakage was caught — so a call on a project class declared in a *sibling* file is measured instead of dropped, and a breakage there can actually be caught. **Adds sites to the denominator, so the reported effectiveness ratio moves** — check it against any `--threshold` you pin in CI before adopting. |
|
|
656
|
+
| `dependent-closure-kill-oracle` | behaviour | [`rigor coverage --protection --mutation`](15-type-protection-coverage.md) counts a breakage as caught when the diagnostic appears anywhere in the mutated file **or the files that depend on it**, instead of in the mutated file alone — so changing what a method returns counts as caught when the error lands in its callers. Can only **add** kills, so the ratio moves up or not at all; it costs about a third more wall time per mutant, and a ratio measured under it is not comparable with one measured without it. |
|
|
657
|
+
|
|
658
|
+
Once a feature **graduates** — it becomes the default at a major
|
|
659
|
+
([ADR-50](../adr/50-release-engineering-and-stability-strategy.md) § WD7)
|
|
660
|
+
— it leaves the queued list and appears under `Graduated`, an
|
|
661
|
+
acknowledgement that naming it in `bleeding_edge:` no longer does
|
|
662
|
+
anything: the behaviour is on for everyone. The section is absent while
|
|
663
|
+
nothing has graduated. In `--format json` the same information is the
|
|
664
|
+
`graduated` array, alongside `overlay` (every queued feature, each with
|
|
665
|
+
its `kind`), `active`, and `unknown_selected`.
|
|
606
666
|
|
|
607
667
|
## `rigor doctor`
|
|
608
668
|
|
|
@@ -116,7 +116,22 @@ statically and may resolve at run time. The same findings appear in the
|
|
|
116
116
|
| `severity_profile` | String | `"balanced"` | `lenient`, `balanced`, or `strict` — see [Diagnostics](04-diagnostics.md). |
|
|
117
117
|
| `severity_overrides` | Hash | `{}` | Per-rule / per-family severity, e.g. `{ call: warning, flow.always-truthy-condition: off }`. |
|
|
118
118
|
| `baseline` | String / `false` | `nil` | Path to a `.rigor-baseline.yml`, or `false` to disable an inherited one. See [Baselines](06-baseline.md). |
|
|
119
|
-
| `bleeding_edge` | Boolean / Array / Hash | `false` | Adopt the next major's queued
|
|
119
|
+
| `bleeding_edge` | Boolean / Array / Hash | `false` | Adopt the next major's queued changes early ([ADR-50](../adr/50-release-engineering-and-stability-strategy.md) § WD2). `false` adopts none; `true` adopts the whole overlay; a list of feature ids adopts only those; `{ all: true, except: [ids] }` adopts all but the named. Orthogonal to `severity_profile`. Override it for a single run with [`rigor check --bleeding-edge[=ids]`](02-cli-reference.md#rigor-check) / `--no-bleeding-edge`. Inspect with [`rigor show-bleedingedge`](02-cli-reference.md#rigor-show-bleedingedge). |
|
|
120
|
+
|
|
121
|
+
A queued feature is one of two kinds, and `bleeding_edge:` selects both the
|
|
122
|
+
same way:
|
|
123
|
+
|
|
124
|
+
- A **severity** feature promotes one or more rules — a discipline Rigor
|
|
125
|
+
already reports quietly becomes an error or a warning. Its diff is a list
|
|
126
|
+
of rule ids, printed by `rigor show-bleedingedge`.
|
|
127
|
+
- A **behaviour** feature changes a measurement, an algorithm, or a
|
|
128
|
+
default, and moves no rule's severity. There is no rule-id diff to read,
|
|
129
|
+
so its summary in `rigor show-bleedingedge` is the whole description of
|
|
130
|
+
what adopting it does.
|
|
131
|
+
|
|
132
|
+
An id you name that this version of Rigor does not know is ignored rather
|
|
133
|
+
than rejected, so a shared `.rigor.yml` can name a feature that only some
|
|
134
|
+
of the versions in use have queued.
|
|
120
135
|
|
|
121
136
|
### Dependency RBS discovery
|
|
122
137
|
|