rigortype 0.4.7 → 0.4.8
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 +3 -1
- data/data/core_overlay/bigdecimal.rbs +33 -0
- data/data/core_overlay/resolv.rbs +30 -0
- data/data/gem_overlay/activesupport/core_ext.rbs +29 -0
- data/data/gem_overlay/addressable/addressable.rbs +40 -0
- data/docs/handbook/01-getting-started.md +1 -1
- data/docs/handbook/11-sig-gen.md +35 -0
- data/docs/install.md +20 -0
- data/docs/manual/01-installation.md +67 -26
- data/docs/manual/02-cli-reference.md +307 -91
- data/docs/manual/03-configuration.md +41 -3
- data/docs/manual/04-diagnostics.md +5 -4
- data/docs/manual/08-skills.md +11 -0
- data/docs/manual/09-editor-integration.md +8 -0
- data/docs/manual/14-rails-quickstart.md +1 -1
- data/docs/manual/19-effect-labels.md +3 -4
- data/docs/manual/plugins/rigor-actionpack.md +15 -6
- data/docs/manual/plugins/rigor-activesupport-core-ext.md +3 -0
- data/docs/manual/plugins/rigor-sorbet.md +17 -3
- data/lib/rigor/analysis/check_rules/always_raises_shield.rb +147 -0
- data/lib/rigor/analysis/check_rules/call_facts.rb +58 -0
- data/lib/rigor/analysis/check_rules/declaration_sourced_guard.rb +8 -0
- data/lib/rigor/analysis/check_rules/ivar_write_collector.rb +13 -2
- data/lib/rigor/analysis/check_rules/lexical_method_sites.rb +6 -0
- data/lib/rigor/analysis/check_rules/plugin_api_surface.rb +195 -0
- data/lib/rigor/analysis/check_rules/published_constant_guard.rb +40 -11
- data/lib/rigor/analysis/check_rules/rbs_receiver_surface.rb +27 -1
- data/lib/rigor/analysis/check_rules/replaced_singleton_defs.rb +96 -0
- data/lib/rigor/analysis/check_rules/rule_ids.rb +8 -1
- data/lib/rigor/analysis/check_rules/void_value_use_collector.rb +1 -1
- data/lib/rigor/analysis/check_rules.rb +598 -99
- data/lib/rigor/analysis/crash_signature.rb +43 -1
- data/lib/rigor/analysis/dependency_recorder.rb +233 -76
- data/lib/rigor/analysis/incremental.rb +11 -1
- data/lib/rigor/analysis/incremental_run_slot/write_guard.rb +2 -1
- data/lib/rigor/analysis/incremental_session.rb +279 -37
- data/lib/rigor/analysis/reachability/plugin_roots.rb +6 -3
- data/lib/rigor/analysis/rule_catalog.rb +37 -1
- data/lib/rigor/analysis/run_cache_key.rb +27 -3
- data/lib/rigor/analysis/run_disclosure_credit.rb +26 -6
- data/lib/rigor/analysis/runner/buffer_pool_dispatcher.rb +4 -0
- data/lib/rigor/analysis/runner/declaration_position.rb +7 -7
- data/lib/rigor/analysis/runner/diagnostic_aggregator.rb +72 -20
- data/lib/rigor/analysis/runner/effect_envelope_pass.rb +3 -8
- data/lib/rigor/analysis/runner/pool_coordinator.rb +26 -5
- data/lib/rigor/analysis/runner/project_pre_passes.rb +4 -37
- data/lib/rigor/analysis/runner.rb +222 -39
- data/lib/rigor/analysis/self_call_resolution_recorder.rb +61 -22
- data/lib/rigor/analysis/worker_session.rb +42 -41
- data/lib/rigor/bleeding_edge.rb +19 -4
- data/lib/rigor/cache/file_digest.rb +39 -31
- data/lib/rigor/cache/incremental_snapshot.rb +66 -7
- data/lib/rigor/cache/rbs_descriptor.rb +37 -2
- data/lib/rigor/cache/rbs_environment.rb +5 -1
- data/lib/rigor/cli/baseline_command.rb +15 -2
- data/lib/rigor/cli/check_command.rb +4 -2
- data/lib/rigor/cli/effects_snapshot_command.rb +8 -1
- data/lib/rigor/cli/lens_command.rb +17 -2
- data/lib/rigor/cli/sig_gen_command.rb +8 -0
- data/lib/rigor/cli/skill_describe.rb +1 -0
- data/lib/rigor/cli.rb +5 -2
- data/lib/rigor/config_audit.rb +32 -18
- data/lib/rigor/configuration/severity_profile.rb +9 -0
- data/lib/rigor/configuration.rb +32 -5
- data/lib/rigor/effects/collector.rb +53 -21
- data/lib/rigor/environment/bundle_sig_discovery.rb +63 -28
- data/lib/rigor/environment/constant_type_cache_holder.rb +5 -0
- data/lib/rigor/environment/default_libraries.rb +17 -0
- data/lib/rigor/environment/deferred_signature_plan.rb +104 -6
- data/lib/rigor/environment/hkt_registry_holder.rb +6 -0
- data/lib/rigor/environment/rbs_collection_discovery.rb +123 -8
- data/lib/rigor/environment/rbs_coverage_report.rb +12 -11
- data/lib/rigor/environment/rbs_hierarchy.rb +6 -0
- data/lib/rigor/environment/rbs_loader.rb +312 -63
- data/lib/rigor/environment.rb +131 -35
- data/lib/rigor/inference/acceptance.rb +50 -15
- data/lib/rigor/inference/alias_mutation_floor/foreign_locals.rb +117 -0
- data/lib/rigor/inference/alias_mutation_floor/memos.rb +85 -0
- data/lib/rigor/inference/alias_mutation_floor/reach.rb +119 -0
- data/lib/rigor/inference/alias_mutation_floor/site_collector.rb +252 -0
- data/lib/rigor/inference/alias_mutation_floor.rb +339 -0
- data/lib/rigor/inference/anonymous_meta_class.rb +18 -0
- data/lib/rigor/inference/block_auto_splat.rb +1 -1
- data/lib/rigor/inference/block_run_count.rb +9 -2
- data/lib/rigor/inference/builtins/array_catalog.rb +2 -2
- data/lib/rigor/inference/callee_mutation_chain.rb +1 -1
- data/lib/rigor/inference/captured_locals.rb +2 -0
- data/lib/rigor/inference/census_foreign_block.rb +354 -0
- data/lib/rigor/inference/clause_widening.rb +1 -1
- data/lib/rigor/inference/closure_escape_analyzer.rb +11 -4
- data/lib/rigor/inference/construction_escape.rb +56 -15
- data/lib/rigor/inference/declaration_walk.rb +4 -0
- data/lib/rigor/inference/def_node_resolver.rb +32 -14
- data/lib/rigor/inference/def_return_typer.rb +1 -1
- data/lib/rigor/inference/definer_resolution.rb +15 -7
- data/lib/rigor/inference/definers_index.rb +72 -16
- data/lib/rigor/inference/error_info.rb +16 -0
- data/lib/rigor/inference/expression_typer.rb +1459 -287
- data/lib/rigor/inference/flow_tracer.rb +31 -14
- data/lib/rigor/inference/fork_map.rb +3 -0
- data/lib/rigor/inference/fresh_frame_blocks.rb +52 -1
- data/lib/rigor/inference/global_write_census.rb +8 -6
- data/lib/rigor/inference/in_effect_refinements.rb +7 -0
- data/lib/rigor/inference/indexed_narrowing.rb +57 -8
- data/lib/rigor/inference/ivar_writer_census.rb +106 -11
- data/lib/rigor/inference/key_presence_guard.rb +51 -25
- data/lib/rigor/inference/last_line/self_evidence.rb +30 -0
- data/lib/rigor/inference/last_line.rb +5 -2
- data/lib/rigor/inference/loop_value_record.rb +63 -15
- data/lib/rigor/inference/match_rebinding/frame.rb +11 -0
- data/lib/rigor/inference/match_rebinding/yielding_match.rb +74 -18
- data/lib/rigor/inference/match_rebinding.rb +21 -8
- data/lib/rigor/inference/method_dispatcher/block_folding.rb +43 -29
- data/lib/rigor/inference/method_dispatcher/class_keyed_block_params.rb +65 -0
- data/lib/rigor/inference/method_dispatcher/core_enumerable_receiver.rb +44 -0
- data/lib/rigor/inference/method_dispatcher/declared_constructor.rb +151 -0
- data/lib/rigor/inference/method_dispatcher/facet_distribution.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/imprecise_argument.rb +2 -2
- data/lib/rigor/inference/method_dispatcher/interface_shape.rb +181 -0
- data/lib/rigor/inference/method_dispatcher/overload_selector.rb +12 -0
- data/lib/rigor/inference/method_dispatcher/rbs_dispatch.rb +409 -67
- data/lib/rigor/inference/method_dispatcher/self_substitute.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/shape_dispatch.rb +384 -64
- data/lib/rigor/inference/method_dispatcher/singleton_type_params.rb +104 -0
- data/lib/rigor/inference/method_dispatcher.rb +66 -18
- data/lib/rigor/inference/method_parameter_binder.rb +136 -56
- data/lib/rigor/inference/module_function_state/spellings.rb +2 -2
- data/lib/rigor/inference/module_function_state.rb +13 -2
- data/lib/rigor/inference/multi_target_binder.rb +1 -1
- data/lib/rigor/inference/mutation_widening.rb +44 -4
- data/lib/rigor/inference/narrowing.rb +201 -27
- data/lib/rigor/inference/operand_effects.rb +43 -2
- data/lib/rigor/inference/optimistic_origin.rb +133 -8
- data/lib/rigor/inference/origin_lookup.rb +1 -1
- data/lib/rigor/inference/precision_scanner.rb +1 -1
- data/lib/rigor/inference/project_method_ownership.rb +28 -10
- data/lib/rigor/inference/project_patched_methods.rb +65 -13
- data/lib/rigor/inference/project_patched_scanner.rb +120 -25
- data/lib/rigor/inference/project_patched_visibility.rb +39 -3
- data/lib/rigor/inference/rbs_type_translator.rb +68 -15
- data/lib/rigor/inference/receiver_writer_call.rb +67 -0
- data/lib/rigor/inference/recursion_rebinding.rb +157 -0
- data/lib/rigor/inference/refined_dispatch/constructed_class.rb +56 -18
- data/lib/rigor/inference/refined_dispatch/own_method.rb +51 -17
- data/lib/rigor/inference/refined_dispatch.rb +13 -0
- data/lib/rigor/inference/reflective_ivar_write.rb +19 -11
- data/lib/rigor/inference/remover_holder_scan.rb +76 -22
- data/lib/rigor/inference/scope_indexer/class_cvars_collector.rb +13 -6
- data/lib/rigor/inference/scope_indexer/declared_param_writes.rb +12 -11
- data/lib/rigor/inference/scope_indexer/ivar_contributions.rb +188 -28
- data/lib/rigor/inference/scope_indexer/mixin_accumulator.rb +136 -9
- data/lib/rigor/inference/scope_indexer.rb +2079 -183
- data/lib/rigor/inference/self_call_ivar_writes.rb +26 -7
- data/lib/rigor/inference/self_preserving_block.rb +87 -0
- data/lib/rigor/inference/singleton_hook_decline.rb +41 -6
- data/lib/rigor/inference/singleton_object_constant.rb +32 -2
- data/lib/rigor/inference/statement_evaluator.rb +970 -250
- data/lib/rigor/inference/string_mutation.rb +14 -0
- data/lib/rigor/inference/synthetic_method_scanner.rb +35 -11
- data/lib/rigor/inference/toplevel_def_census.rb +14 -6
- data/lib/rigor/inference/unknown_store_widening.rb +1 -1
- data/lib/rigor/inference/untyped_rejoin.rb +1 -1
- data/lib/rigor/inference/void_tail_summary.rb +29 -10
- data/lib/rigor/lens/claims/comparison.rb +78 -0
- data/lib/rigor/lens/claims/request.rb +131 -0
- data/lib/rigor/lens/claims/type_reader.rb +216 -0
- data/lib/rigor/lens/claims.rb +208 -0
- data/lib/rigor/lens/contract_reader.rb +5 -0
- data/lib/rigor/lens/document.rb +1 -1
- data/lib/rigor/lens/file_reader.rb +21 -8
- data/lib/rigor/lens/run.rb +8 -0
- data/lib/rigor/lens.rb +1 -1
- data/lib/rigor/library_probe.rb +68 -0
- data/lib/rigor/memo_audit.rb +282 -0
- data/lib/rigor/plugin/base.rb +15 -2
- data/lib/rigor/plugin/io_boundary.rb +25 -3
- data/lib/rigor/plugin/manifest.rb +7 -3
- data/lib/rigor/plugin/registry.rb +13 -2
- data/lib/rigor/plugin/trust_policy.rb +46 -0
- data/lib/rigor/protection/mutation_cache.rb +4 -1
- data/lib/rigor/reflection/constant_ancestors.rb +79 -22
- data/lib/rigor/reflection/declaration_collectors.rb +55 -0
- data/lib/rigor/reflection/declarations.rb +58 -0
- data/lib/rigor/reflection/project_method.rb +177 -0
- data/lib/rigor/reflection.rb +2 -0
- data/lib/rigor/rooted_glob.rb +18 -1
- data/lib/rigor/run_scoped_slots.rb +20 -20
- data/lib/rigor/scope/discovery_index.rb +149 -2
- data/lib/rigor/scope/resolution_chain/relevance.rb +14 -1
- data/lib/rigor/scope/resolution_chain.rb +900 -55
- data/lib/rigor/scope.rb +307 -34
- data/lib/rigor/sig_gen/bot_proposal_guard.rb +306 -0
- data/lib/rigor/sig_gen/classification.rb +14 -1
- data/lib/rigor/sig_gen/generator.rb +222 -13
- data/lib/rigor/sig_gen/method_candidate.rb +14 -0
- data/lib/rigor/sig_gen/observation_collector.rb +11 -2
- data/lib/rigor/sig_gen/platform_guarded_files.rb +184 -0
- data/lib/rigor/sig_gen/skip_reason_catalog.rb +47 -0
- data/lib/rigor/sig_gen/writer.rb +21 -0
- data/lib/rigor/sig_gen.rb +1 -0
- data/lib/rigor/source/forwardable_delegators.rb +122 -0
- data/lib/rigor/source/node_children.rb +13 -0
- data/lib/rigor/type/combinator.rb +164 -8
- data/lib/rigor/type/interface.rb +60 -0
- data/lib/rigor/type.rb +1 -0
- data/lib/rigor/type_of_memo/serving.rb +99 -0
- data/lib/rigor/type_of_memo/stats.rb +43 -0
- data/lib/rigor/type_of_memo.rb +337 -0
- data/lib/rigor/typing_state.rb +1094 -0
- data/lib/rigor/version.rb +1 -1
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/view_assigns.rb +2 -2
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack.rb +57 -25
- data/plugins/rigor-active-model-serializers/lib/rigor/plugin/active_model_serializers.rb +3 -6
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/analyzer.rb +25 -1
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_discoverer.rb +16 -6
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_index.rb +4 -2
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/analyzer.rb +2 -1
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_parser.rb +130 -30
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_table.rb +20 -5
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/structure_sql_parser.rb +7 -4
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord.rb +49 -13
- data/plugins/rigor-activerecord/sig/active_record/relation.rbs +19 -5
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage.rb +4 -2
- data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext.rb +13 -5
- data/plugins/rigor-activesupport-core-ext/sig/active_support/core_ext.rbs +29 -0
- data/plugins/rigor-alba/lib/rigor/plugin/alba/resource_collector.rb +15 -21
- data/plugins/rigor-alba/lib/rigor/plugin/alba/resource_discoverer.rb +1 -6
- data/plugins/rigor-ffi/lib/rigor/plugin/ffi.rb +4 -2
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql.rb +12 -2
- data/plugins/rigor-mangrove/lib/rigor/plugin/mangrove.rb +6 -0
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/analyzer.rb +199 -1
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes.rb +3 -2
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/matcher_analyzer.rb +4 -4
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog.rb +209 -2
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog_walker.rb +146 -7
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/type_translator.rb +52 -34
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet.rb +80 -3
- data/plugins/rigor-typelizer/lib/rigor/plugin/typelizer/serializer_collector.rb +16 -16
- data/plugins/rigor-typelizer/lib/rigor/plugin/typelizer/serializer_discoverer.rb +1 -6
- data/sig/rigor/analysis/check_rules/rule_walk.rbs +6 -0
- data/sig/rigor/analysis/fact_store.rbs +2 -3
- data/sig/rigor/cache/descriptor.rbs +14 -0
- data/sig/rigor/environment.rbs +4 -1
- data/sig/rigor/plugin/base.rbs +53 -19
- data/sig/rigor/plugin/interfaces.rbs +51 -0
- data/sig/rigor/plugin/io_boundary.rbs +2 -3
- data/sig/rigor/plugin/node_context.rbs +21 -0
- data/sig/rigor/reflection.rbs +37 -0
- data/sig/rigor/scope.rbs +22 -3
- data/sig/rigor/trinary.rbs +1 -0
- data/sig/rigor/type.rbs +9 -3
- data/sig/rigor.rbs +3 -2
- data/skills/rigor-ask/SKILL.md +1 -0
- data/skills/rigor-project-init/references/01-detect.md +1 -0
- data/skills/rigor-project-init/references/03-baseline-and-bugs.md +5 -1
- data/skills/rigor-project-init/references/06-agent-contract.md +4 -4
- data/skills/rigor-rbs-contract/SKILL.md +147 -0
- data/skills/rigor-rbs-contract/references/01-finding-candidates.md +212 -0
- data/skills/rigor-rbs-contract/references/02-contract-rules.md +157 -0
- data/skills/rigor-rbs-contract/references/03-target-own-code.md +90 -0
- data/skills/rigor-rbs-contract/references/04-target-gem-rbs-collection.md +210 -0
- data/skills/rigor-rbs-contract/references/05-declaration-mutants.md +182 -0
- data/skills/rigor-rbs-setup/SKILL.md +3 -1
- data/skills/rigor-type-oracle/SKILL.md +26 -1
- data/skills/rigor-type-oracle/references/02-agents-md-fragment.md +4 -3
- metadata +48 -2
- data/lib/rigor/inference/memo_audit.rb +0 -55
|
@@ -148,22 +148,38 @@ when a lockfile is present.
|
|
|
148
148
|
|
|
149
149
|
## `rigor annotate`
|
|
150
150
|
|
|
151
|
-
Reprint a file with every line tagged by the type of the
|
|
152
|
-
expression it evaluates to, as a trailing `#=>` comment. See
|
|
153
|
-
[Inspecting inferred types](05-inspecting-types.md).
|
|
151
|
+
Reprint a source file with every line tagged by the inferred type of the expression it evaluates to, as a trailing `#=>` comment (following the xmpfilter / seeing_is_believing convention). See [Inspecting inferred types](05-inspecting-types.md).
|
|
154
152
|
|
|
155
153
|
```sh
|
|
156
|
-
rigor annotate [
|
|
154
|
+
rigor annotate [options] FILE
|
|
157
155
|
```
|
|
158
156
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
`
|
|
163
|
-
`--
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
157
|
+
| Flag | Purpose |
|
|
158
|
+
| --- | --- |
|
|
159
|
+
| `--config=PATH` | Path to `.rigor.yml`. Overrides auto-discovery. |
|
|
160
|
+
| `--format=FORMAT` | Output format (`text` or `json`). Default: `text`. |
|
|
161
|
+
| `--[no-]color` | Force or disable ANSI color (default: auto-detected for a tty; honors `NO_COLOR`). |
|
|
162
|
+
| `--[no-]bat` | Force or disable syntax highlighting through [`bat`](https://github.com/sharkdp/bat) (default: enabled when color is on and `bat` is found on `PATH`). |
|
|
163
|
+
|
|
164
|
+
The positional `FILE` argument is required. For each line, the command locates the last expression evaluated on that line (e.g. the last statement in `1; 2; 3` reports `3`, and a conditional header `if nil` reports its condition) and annotates it with `#=> <type>`. On method definition headers (`def`), the line is annotated with the method's inferred return type rather than the header expression.
|
|
165
|
+
|
|
166
|
+
Annotations are idempotent: re-running `rigor annotate` matches existing `#=>` comments (as well as legacy `#=> dump_type:` comments) and replaces them in-place instead of stacking comments.
|
|
167
|
+
|
|
168
|
+
When color is enabled and `bat` is installed, output is syntax-highlighted via `bat --language=ruby --style=plain --paging=never`. Passing `--no-bat` disables `bat` integration in favor of Rigor's built-in Prism colorizer. `--bat` warns on stderr and falls back to the built-in colorizer if `bat` is not found on `PATH`.
|
|
169
|
+
|
|
170
|
+
In `--format=json`, the command emits a JSON object mapping line numbers to type strings conforming to schema version 1:
|
|
171
|
+
|
|
172
|
+
```json
|
|
173
|
+
{
|
|
174
|
+
"schema_version": 1,
|
|
175
|
+
"annotations": {
|
|
176
|
+
"1": "Integer",
|
|
177
|
+
"2": "String | nil"
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
Exit `0` on success, `1` if the file does not exist or contains a Prism syntax error, and `64` on usage errors (such as a missing `FILE` argument).
|
|
167
183
|
|
|
168
184
|
## JSON documents
|
|
169
185
|
|
|
@@ -249,58 +265,144 @@ against `rigor check --no-cache` removes that variable.
|
|
|
249
265
|
|
|
250
266
|
## `rigor lens`
|
|
251
267
|
|
|
252
|
-
Map the declarations of one or more files with their types and
|
|
253
|
-
type provenance (experimental). See
|
|
254
|
-
[Inspecting inferred types](05-inspecting-types.md).
|
|
268
|
+
Map the declarations of one or more files with their types and type provenance (experimental). See [Inspecting inferred types](05-inspecting-types.md).
|
|
255
269
|
|
|
256
270
|
```sh
|
|
257
|
-
rigor lens [
|
|
271
|
+
rigor lens [options] FILE...
|
|
258
272
|
```
|
|
259
273
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
`--
|
|
263
|
-
`
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
274
|
+
| Flag | Purpose |
|
|
275
|
+
| --- | --- |
|
|
276
|
+
| `--config=PATH` | Path to `.rigor.yml`. Overrides auto-discovery. |
|
|
277
|
+
| `--format=FORMAT` | Output format (`text` or `json`). Default: `text`. |
|
|
278
|
+
| `--workers=N` | Worker process count for a cold run. |
|
|
279
|
+
| `--claims=REQUEST` | Check documentation type claims against authored contracts (unreleased). Requires `--format=json`. |
|
|
280
|
+
|
|
281
|
+
`rigor lens` performs the same incremental analysis as `rigor check --incremental` and shares its cache (`.rigor/cache`). The first execution on a file costs a full check, while subsequent runs reuse the recorded cache.
|
|
282
|
+
|
|
283
|
+
`--claims=REQUEST` checks documentation type claims against authored contracts in the same run (unreleased). It requires `--format=json` and a UTF-8 JSON request following the [claims contract](../internal-spec/lens-claims.md). The `claims` section reports each claim's verdict; a conflict does not change the exit status. An invalid or stale request exits `64` without a document. Claims do not alter analysis, diagnostics or cached types.
|
|
284
|
+
|
|
285
|
+
### Text representation
|
|
286
|
+
|
|
287
|
+
Text output lists each declaration preceded by an anchor identifier:
|
|
288
|
+
|
|
289
|
+
```text
|
|
290
|
+
lib/shop.rb xxh3-64:845f7426b6acfe12 (2 omitted)
|
|
291
|
+
4:7c90 class Shop
|
|
292
|
+
8:e37e Shop#label: (::Integer n) -> ::String [contract inline]
|
|
293
|
+
14:ce93 Shop#total: () -> Integer [single_site inferred]
|
|
294
|
+
16:182b Shop#fetch [contested; also lib/legacy_shop.rb:2]
|
|
295
|
+
omitted constant Shop::LIMIT (line 5)
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
- **`LINE:HASH`**: Stable anchor hash identifying the declaration. It changes when the declaration signature or preceding type comments change, but remains unchanged across prose comment edits.
|
|
299
|
+
- **`provenance`**: The origin of the type in square brackets (e.g. `[contract sig]`, `[contract inline]`, `[single_site inferred]`, `[plugin <name>]`).
|
|
300
|
+
- **`contested`**: Denotes methods where multiple definitions exist in the project (e.g. reopened classes across files); Rigor prints no signature rather than guessing runtime dispatch.
|
|
301
|
+
- **`omitted`**: Constructs not yet modeled by the lens (constants, `alias`, `define_method`) are explicitly recorded as omitted rather than discarded.
|
|
302
|
+
|
|
303
|
+
In `--format=json`, the command outputs a `lens/v0` JSON document (specified in [the lens output contract](../internal-spec/lens.md)).
|
|
304
|
+
|
|
305
|
+
Exit `0` when at least one input file is successfully analysed (`status: "ok"`), `1` when no target achieves `status: "ok"` (the JSON document is still written to stdout), and `64` on usage errors (such as missing `FILE` arguments or an unreadable `--config` path). Diagnostics present in the analysed files do not affect the exit code.
|
|
267
306
|
|
|
268
307
|
## `rigor trace`
|
|
269
308
|
|
|
270
|
-
Replay
|
|
271
|
-
terminal animation. It is a teaching probe over the same
|
|
272
|
-
inference `rigor check` runs.
|
|
309
|
+
Replay how the engine typed a file step-by-step as an interactive terminal animation. It is a teaching and debugging probe operating over the inference engine. See [Inspecting inferred types](05-inspecting-types.md).
|
|
273
310
|
|
|
274
311
|
```sh
|
|
275
|
-
rigor trace [
|
|
312
|
+
rigor trace [options] FILE
|
|
276
313
|
```
|
|
277
314
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
315
|
+
| Flag | Purpose |
|
|
316
|
+
| --- | --- |
|
|
317
|
+
| `--config=PATH` | Path to `.rigor.yml`. Overrides auto-discovery. |
|
|
318
|
+
| `--delay=SECONDS` | Autoplay frames with `SECONDS` delay between steps (default: step manually on key press). |
|
|
319
|
+
| `--line=N` | Replay only inference events whose source range starts on line `N`. |
|
|
320
|
+
| `--verbose` | Include every expression `enter` and `result` frame (default: only teachable inference milestones). |
|
|
321
|
+
| `--format=FORMAT` | Output format: `text` (interactive terminal animation) or `json` (raw event stream). Default: `text`. |
|
|
322
|
+
|
|
323
|
+
### Inference events
|
|
324
|
+
|
|
325
|
+
By default, the replay highlights the AST expression being evaluated alongside the current local variable environment, presenting three core inference event kinds:
|
|
326
|
+
- **`bind`**: A local variable binding enters the active scope.
|
|
327
|
+
- **`union`**: Types from distinct control-flow branches merge into a union type.
|
|
328
|
+
- **`dispatch`**: A method call resolves against its receiver or falls back to `Dynamic[top]`.
|
|
329
|
+
|
|
330
|
+
With `--verbose`, every AST node entry and evaluated type result is captured as a frame.
|
|
331
|
+
|
|
332
|
+
### Interactive navigation
|
|
333
|
+
|
|
334
|
+
On a terminal TTY, the animation advances one frame per key press. Press `q` to exit playback early. Specifying `--delay=SECONDS` enables hands-free autoplay.
|
|
335
|
+
|
|
336
|
+
In `--format=json`, the raw stream of event objects is emitted as a top-level JSON array for external tooling or courseware integration. Like `rigor explain`, it prints a deprecation notice on stderr noting the upcoming `schema_version: 1` envelope migration (see [JSON documents](#json-documents)).
|
|
337
|
+
|
|
338
|
+
Exit `0` on successful playback or stream emission, `1` if the file does not exist or contains syntax errors (Prism parse errors), and `64` on usage errors (such as missing `FILE`, passing multiple files, or invalid flags).
|
|
288
339
|
|
|
289
340
|
## `rigor type-scan`
|
|
290
341
|
|
|
291
|
-
Report `type_of` inference coverage across paths —
|
|
292
|
-
diagnostic-of-the-diagnoser, useful when investigating why a
|
|
293
|
-
class infers poorly.
|
|
342
|
+
Report `Scope#type_of` inference coverage across paths — an engine diagnostic measuring how much of the target source is directly typed without falling back to `Dynamic[top]`.
|
|
294
343
|
|
|
295
344
|
```sh
|
|
296
|
-
rigor type-scan PATH...
|
|
345
|
+
rigor type-scan [options] PATH...
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
| Flag | Purpose |
|
|
349
|
+
| --- | --- |
|
|
350
|
+
| `--config=PATH` | Path to `.rigor.yml`. Overrides auto-discovery. |
|
|
351
|
+
| `--format=FORMAT` | Output format (`text` or `json`). Default: `text`. |
|
|
352
|
+
| `--limit=N` | Maximum unrecognized example events to display in text mode. Default: `10`. |
|
|
353
|
+
| `--show-recognized` | Include AST node classes with 0 unrecognized visits in the summary table. |
|
|
354
|
+
| `--threshold=RATIO` | Exit non-zero (`1`) when the ratio of unrecognized nodes (`unrecognized / visits`) exceeds `RATIO` (float). |
|
|
355
|
+
|
|
356
|
+
At least one `PATH` argument is required. The command traverses every Prism node across the specified paths and queries `Scope#type_of` against a discovery-seeded project environment (matching `rigor coverage`).
|
|
357
|
+
|
|
358
|
+
### Output format
|
|
359
|
+
|
|
360
|
+
In text mode, `rigor type-scan` prints a summary block, class breakdown, and unrecognized examples:
|
|
361
|
+
|
|
362
|
+
```text
|
|
363
|
+
Type-of scan: 1 file
|
|
364
|
+
- lib/user.rb
|
|
365
|
+
|
|
366
|
+
Summary:
|
|
367
|
+
files processed: 1
|
|
368
|
+
parse errors: 0
|
|
369
|
+
AST nodes visited: 165
|
|
370
|
+
unrecognized: 14 ( 8.5%)
|
|
371
|
+
|
|
372
|
+
Coverage by node class (unrecognized/visits):
|
|
373
|
+
Prism::CallNode 12/120 ( 10.0%)
|
|
374
|
+
Prism::ConstantReadNode 2/ 45 ( 4.4%)
|
|
375
|
+
|
|
376
|
+
Unrecognized examples (showing 10 of 14):
|
|
377
|
+
Prism::CallNode @ lib/user.rb:14:5
|
|
297
378
|
```
|
|
298
379
|
|
|
299
|
-
`--limit=N` caps the
|
|
300
|
-
|
|
301
|
-
`--
|
|
302
|
-
|
|
303
|
-
|
|
380
|
+
Passing `--show-recognized` includes node classes with 0 unrecognized visits in the class breakdown. `--limit=N` caps the total number of examples shown in the unrecognized events section.
|
|
381
|
+
|
|
382
|
+
In `--format=json`, the command emits a JSON document conforming to schema version 1:
|
|
383
|
+
|
|
384
|
+
```json
|
|
385
|
+
{
|
|
386
|
+
"schema_version": 1,
|
|
387
|
+
"files": [ "lib/user.rb" ],
|
|
388
|
+
"summary": {
|
|
389
|
+
"files_processed": 1,
|
|
390
|
+
"parse_errors": 0,
|
|
391
|
+
"visited": 165,
|
|
392
|
+
"unrecognized": 14,
|
|
393
|
+
"unrecognized_ratio": 0.0848
|
|
394
|
+
},
|
|
395
|
+
"by_class": {
|
|
396
|
+
"Prism::CallNode": { "visits": 120, "unrecognized": 12 }
|
|
397
|
+
},
|
|
398
|
+
"events": [
|
|
399
|
+
{ "file": "lib/user.rb", "node_class": "Prism::CallNode", "family": "call", "line": 14, "column": 5 }
|
|
400
|
+
],
|
|
401
|
+
"parse_errors": []
|
|
402
|
+
}
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
Exit `0` if the unrecognized ratio is within `--threshold` (or when no threshold is set) and no parse errors occurred. Exit `1` if the ratio exceeds `--threshold` or if any scanned file contains parse errors. Exit `64` if no paths are provided, a specified path does not exist, or flags are invalid.
|
|
304
406
|
|
|
305
407
|
## `rigor effects`
|
|
306
408
|
|
|
@@ -433,6 +535,12 @@ origin/main:.rigor-effects.yml)` in a bot),
|
|
|
433
535
|
`explain` additionally accepts `--symbol=KEY` to explain one
|
|
434
536
|
specific unit instead of the changed ones.
|
|
435
537
|
|
|
538
|
+
`update` writes `effects.snapshot.path:` (default
|
|
539
|
+
`.rigor-effects.yml`). A path whose directory does not exist, or
|
|
540
|
+
that cannot be written, is a usage error: one
|
|
541
|
+
`rigor effects: cannot write PATH: REASON` line on stderr and
|
|
542
|
+
exit `64`. The directory is not created.
|
|
543
|
+
|
|
436
544
|
The file records two tables. `methods:` holds each method's
|
|
437
545
|
**direct** summary — what its own body does, block literals
|
|
438
546
|
and catalogued callees included, but not what the project
|
|
@@ -550,38 +658,107 @@ reviewer's judgment, which is what makes it a review artefact.
|
|
|
550
658
|
|
|
551
659
|
## `rigor explain`
|
|
552
660
|
|
|
553
|
-
Print the catalogue entry for a diagnostic rule, or list every
|
|
554
|
-
rule when called with no argument.
|
|
661
|
+
Print the catalogue entry for a diagnostic rule, or list every rule when called with no argument.
|
|
555
662
|
|
|
556
663
|
```sh
|
|
557
|
-
rigor explain [options] [rule]
|
|
664
|
+
rigor explain [options] [<rule>]
|
|
558
665
|
```
|
|
559
666
|
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
`
|
|
563
|
-
|
|
667
|
+
| Flag | Purpose |
|
|
668
|
+
| --- | --- |
|
|
669
|
+
| `--format=FORMAT` | Output format (`text` or `json`). Default: `text`. |
|
|
670
|
+
|
|
671
|
+
### Invocation modes
|
|
672
|
+
|
|
673
|
+
| Form | Purpose |
|
|
674
|
+
| --- | --- |
|
|
675
|
+
| (none) | Print the complete rule catalogue index (rule ID and one-line summary) followed by every `rigor sig-gen` skip reason. |
|
|
676
|
+
| `<rule>` | Print the full catalogue entry for a canonical rule ID (e.g. `call.undefined-method`) or a legacy alias (e.g. `undefined-method`). |
|
|
677
|
+
| `<family>` | Family wildcard (`call`, `flow`, `def`, `assert`, `dump`, `global`, `suppression`, `static`, `effect`). Prints every rule under that prefix. |
|
|
678
|
+
| `<skip-reason>` | Print the explanation and recommended next action for an exact `rigor sig-gen` skip reason token (e.g. `sig.skipped.untyped-return`). Does not accept wildcards. |
|
|
679
|
+
|
|
680
|
+
A rule entry includes its summary, legacy aliases, authored severity, severity mapped across configuration profiles (`lenient`, `balanced`, `strict`), evidence tier, `Fires when:` conditions, `Does not fire when:` exceptions, inline suppression syntax (`# rigor:disable <rule>`), documentation link, and the Rigor release where the rule was introduced.
|
|
681
|
+
|
|
682
|
+
A `<skip-reason>` token explains why `rigor sig-gen` declined to write a signature (such as dynamic returns or unbounded blocks) and suggests what to address instead. Because skip reasons report signatures that were not written rather than code findings, they carry no severity and nothing to suppress.
|
|
564
683
|
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
instead. Those are not diagnostic rules, so they are rendered without
|
|
569
|
-
a severity or a suppression line.
|
|
684
|
+
In `--format=json`, diagnostic rules (whether requested by a single rule ID, legacy alias, family wildcard, or with no arguments) always emit a JSON array of catalogue entry objects. In contrast, querying an individual `<skip-reason>` emits a single JSON object. In the index mode with no arguments, `--format=json` outputs only the diagnostic rule array; individual skip reasons must be queried by token. Top-level JSON shapes currently print a stderr deprecation notice regarding the future envelope migration (see [JSON documents](#json-documents)).
|
|
685
|
+
|
|
686
|
+
Exit `0` on success, `64` on an unknown rule name or invalid options.
|
|
570
687
|
|
|
571
688
|
## `rigor diff`
|
|
572
689
|
|
|
573
|
-
Compare
|
|
574
|
-
`rigor check --format=json` result and report only what is new.
|
|
690
|
+
Compare current diagnostics against a saved `rigor check --format=json` result and report the delta.
|
|
575
691
|
|
|
576
692
|
```sh
|
|
577
693
|
rigor diff [options] <rigor-check.json> [paths...]
|
|
578
694
|
```
|
|
579
695
|
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
configuration to the implicit check.
|
|
584
|
-
|
|
696
|
+
| Flag | Purpose |
|
|
697
|
+
| --- | --- |
|
|
698
|
+
| `--current=PATH` | Compare against a saved diagnostics JSON file instead of executing a fresh `rigor check` run. |
|
|
699
|
+
| `--config=PATH` | Custom `.rigor.yml` configuration forwarded to the implicit `rigor check` run. Ignored when `--current` is supplied. |
|
|
700
|
+
| `--format=FORMAT` | Output format (`text` or `json`). Default: `text`. |
|
|
701
|
+
|
|
702
|
+
The positional `<rigor-check.json>` file is required. Per ADR-126 § WD1, this file is a saved `rigor check --format=json` result or JSON snapshot, distinct from the rule-bucket `.rigor-baseline.yml` managed by `rigor baseline`.
|
|
703
|
+
|
|
704
|
+
When `[paths...]` are given, only those source paths are evaluated by the implicit check. Note that if `<rigor-check.json>` covers the entire repository, restricting the implicit check to a subset of paths causes all diagnostics in omitted files to be reported as `- FIXED`. When `--current=PATH` is provided, `[paths...]` are ignored.
|
|
705
|
+
|
|
706
|
+
### Identity matching
|
|
707
|
+
|
|
708
|
+
Diagnostic identity is determined by the 6-element tuple:
|
|
709
|
+
|
|
710
|
+
```
|
|
711
|
+
(path, line, column, rule, source_family, message)
|
|
712
|
+
```
|
|
713
|
+
|
|
714
|
+
Diagnostics matching a saved tuple are considered pre-existing. Current diagnostics missing from the saved snapshot are classified as `+ NEW` (regressions). Saved diagnostics missing from the current run are classified as `- FIXED` (progress). Moving code to another line or changing a message produces one fixed and one new entry. Severity is not part of the identity tuple; changing a diagnostic's severity without moving its location does not register as a diff.
|
|
715
|
+
|
|
716
|
+
### Output format
|
|
717
|
+
|
|
718
|
+
Text output reports the diff header, line-by-line additions and removals, and summary counts:
|
|
719
|
+
|
|
720
|
+
```text
|
|
721
|
+
# diff against rigor-check.json (10 baseline / 9 current)
|
|
722
|
+
+ NEW lib/user.rb:14:5 [call.undefined-method] Method `full_name` does not exist on `User`
|
|
723
|
+
- FIXED lib/auth.rb:22:9 [call.argument-type-mismatch] Expected `String`, got `Integer`
|
|
724
|
+
|
|
725
|
+
1 new, 1 fixed
|
|
726
|
+
```
|
|
727
|
+
|
|
728
|
+
With `--format=json`, the output conforms to schema version 1:
|
|
729
|
+
|
|
730
|
+
```json
|
|
731
|
+
{
|
|
732
|
+
"schema_version": 1,
|
|
733
|
+
"baseline": "rigor-check.json",
|
|
734
|
+
"baseline_count": 10,
|
|
735
|
+
"current_count": 9,
|
|
736
|
+
"new": [ ... ],
|
|
737
|
+
"fixed": [ ... ]
|
|
738
|
+
}
|
|
739
|
+
```
|
|
740
|
+
|
|
741
|
+
### CI integration
|
|
742
|
+
|
|
743
|
+
`rigor diff` enables regression gating in repositories adopting Rigor incrementally by catching newly introduced diagnostics without requiring all legacy diagnostics to be fixed first.
|
|
744
|
+
|
|
745
|
+
In standard CI workflows, commit a saved snapshot in-tree (e.g. `rigor-check.json`) generated by `rigor check --format=json > rigor-check.json`. In CI, run:
|
|
746
|
+
|
|
747
|
+
```sh
|
|
748
|
+
rigor diff rigor-check.json
|
|
749
|
+
```
|
|
750
|
+
|
|
751
|
+
When comparing against a dynamic base branch in a multi-step job (where `rigor check` on the base branch may exit non-zero due to pre-existing diagnostics), guard the exit code under `set -e`:
|
|
752
|
+
|
|
753
|
+
```sh
|
|
754
|
+
# On base branch (or via git show / artifact)
|
|
755
|
+
rigor check --format=json > /tmp/base-check.json || true
|
|
756
|
+
|
|
757
|
+
# On PR branch
|
|
758
|
+
rigor diff /tmp/base-check.json
|
|
759
|
+
```
|
|
760
|
+
|
|
761
|
+
Exit `0` when no new diagnostics appear (`new` is empty, even if `fixed` contains entries). Exit `1` when any new diagnostic of any severity (`error`, `warning`, or `info`) appears. Exit `64` if either JSON file is missing, contains invalid JSON, or command usage is incorrect.
|
|
585
762
|
|
|
586
763
|
## `rigor sig-gen`
|
|
587
764
|
|
|
@@ -636,6 +813,11 @@ repair through.
|
|
|
636
813
|
routes to a signature path it does not write to, because it is declared there or its class lives there) on its own `skipped Class#method (reason)` line; the exit status is
|
|
637
814
|
unchanged. See [handbook chapter 11](../handbook/11-sig-gen.md#safety-what---write-will-and-will-not-do).
|
|
638
815
|
|
|
816
|
+
A `sig/` target `--write` cannot write — a permission denial, a directory sitting where the `.rbs`
|
|
817
|
+
belongs, or a parent path that is a regular file — is a usage error: one `rigor sig-gen: cannot
|
|
818
|
+
write PATH: REASON` line on stderr and exit `64`. A missing parent directory is created as before.
|
|
819
|
+
The run stops at the first failure; targets already written stay written.
|
|
820
|
+
|
|
639
821
|
A method declared inline with `# @rbs` / `#:` is written as that
|
|
640
822
|
declaration, not as what its body infers; a parameter-only
|
|
641
823
|
annotation keeps its parameters and takes the return from the body,
|
|
@@ -738,6 +920,12 @@ rigor baseline <generate|regenerate|dump|drift|prune> [options]
|
|
|
738
920
|
`--baseline=PATH` to read a non-default baseline file. `dump`
|
|
739
921
|
also accepts `--format=text|json` for machine-readable output.
|
|
740
922
|
|
|
923
|
+
A write target — `generate` and `regenerate`'s `--output`, or the
|
|
924
|
+
`--baseline` file `prune` rewrites — whose directory does not exist,
|
|
925
|
+
or that cannot be written, is a usage error: one
|
|
926
|
+
`rigor baseline: cannot write PATH: REASON` line on stderr and exit
|
|
927
|
+
`64`. The directory is not created.
|
|
928
|
+
|
|
741
929
|
No subcommand takes a positional path: `generate` and `regenerate`
|
|
742
930
|
analyse the configured `paths:`, `drift` and `prune` audit them, and
|
|
743
931
|
`dump` reads the baseline file and filters with `--rule`/`--file`. A path argument is a usage error
|
|
@@ -1116,15 +1304,28 @@ caveat for container / cross-filesystem setups).
|
|
|
1116
1304
|
|
|
1117
1305
|
## `rigor playground`
|
|
1118
1306
|
|
|
1119
|
-
Start
|
|
1120
|
-
real-time diagnostics). Requires the separate `rigor-playground`
|
|
1121
|
-
gem; if it is not installed the command prints an install hint
|
|
1122
|
-
and exits `64`.
|
|
1307
|
+
Start a local browser playground (a CodeMirror editor with real-time Rigor diagnostics and type inspection).
|
|
1123
1308
|
|
|
1124
1309
|
```sh
|
|
1125
|
-
rigor playground
|
|
1310
|
+
rigor playground [options]
|
|
1311
|
+
```
|
|
1312
|
+
|
|
1313
|
+
| Flag | Purpose |
|
|
1314
|
+
| --- | --- |
|
|
1315
|
+
| `--port=PORT` | Port to bind the playground HTTP server to (default: `9393`). |
|
|
1316
|
+
| `--no-open` | Do not automatically open the playground URL in the default browser on launch. |
|
|
1317
|
+
|
|
1318
|
+
The playground requires the separate `rigor-playground` companion gem. When the gem is not installed in the active Ruby environment, the command prints an installation hint on stderr and exits `64` (`CLI::EXIT_USAGE`):
|
|
1319
|
+
|
|
1320
|
+
```text
|
|
1321
|
+
rigor playground requires the rigor-playground gem.
|
|
1322
|
+
Install it with: gem install rigor-playground
|
|
1126
1323
|
```
|
|
1127
1324
|
|
|
1325
|
+
When installed, the command boots the local web server and opens an interactive browser playground where Ruby code can be written, edited, and analyzed with immediate feedback.
|
|
1326
|
+
|
|
1327
|
+
Exit `0` on clean shutdown, `1` if server startup fails (e.g. port already in use), and `64` if `rigor-playground` is missing or on usage errors.
|
|
1328
|
+
|
|
1128
1329
|
## `rigor skill`
|
|
1129
1330
|
|
|
1130
1331
|
List or print the bundled Agent Skills shipped inside the
|
|
@@ -1182,24 +1383,27 @@ they now read as an unknown skill. Use the forms above.
|
|
|
1182
1383
|
|
|
1183
1384
|
## `rigor describe`
|
|
1184
1385
|
|
|
1185
|
-
Top-level alias for [`rigor skill describe`](#rigor-skill) — the
|
|
1186
|
-
onboarding entry point that recommends the next skill for this project.
|
|
1187
|
-
A bare `rigor describe` is the intuitive guess most users reach for
|
|
1188
|
-
first, so it is surfaced as its own command ([ADR-73](../adr/73-skill-driven-user-experience.md)
|
|
1189
|
-
§ WD2).
|
|
1386
|
+
Top-level alias for [`rigor skill describe`](#rigor-skill) — the onboarding entry point that assesses the project's state and recommends the next skill to run ([ADR-73](../adr/73-skill-driven-user-experience.md) § WD2).
|
|
1190
1387
|
|
|
1191
1388
|
```sh
|
|
1192
|
-
rigor describe
|
|
1389
|
+
rigor describe [--deep]
|
|
1193
1390
|
```
|
|
1194
1391
|
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1392
|
+
| Flag | Purpose |
|
|
1393
|
+
| --- | --- |
|
|
1394
|
+
| `--deep` | Run `rigor check` first and route the headline recommendation on the diagnostic results. |
|
|
1395
|
+
|
|
1396
|
+
### Audit modes
|
|
1397
|
+
|
|
1398
|
+
By default, `rigor describe` performs a presence-only probe checking for the existence of `.rigor.yml`, `.rigor-baseline.yml`, a `sig/` directory, and CI configurations. This default mode is read-only, fast, and side-effect-free — it never executes `rigor check` and never reads or writes `.rigor/cache`.
|
|
1199
1399
|
|
|
1200
|
-
`
|
|
1201
|
-
|
|
1202
|
-
|
|
1400
|
+
Passing `--deep` opts into running `rigor check` before generating recommendations, routing based on analysis health:
|
|
1401
|
+
- **`rigor-doctor`**: Selected if the RBS environment builds with 0 classes or any `configuration-error` diagnostic is raised.
|
|
1402
|
+
- **`rigor-monkeypatch-resolve`**: Selected if at least one third of remaining error diagnostics stem from calls resolving to project-side reopened core or gem definitions (addressable via `pre_eval:`).
|
|
1403
|
+
- **`rigor-baseline-reduce`**: Selected when remaining error diagnostics exist.
|
|
1404
|
+
- **Presence-only recommendation**: Retained when the analysis is completely clean or when no configuration exists yet.
|
|
1405
|
+
|
|
1406
|
+
Output is identical to `rigor skill describe`. Exit `0` on completion, or `64` on invalid options.
|
|
1203
1407
|
|
|
1204
1408
|
## `rigor docs`
|
|
1205
1409
|
|
|
@@ -1265,9 +1469,10 @@ Queued today:
|
|
|
1265
1469
|
| --- | --- | --- |
|
|
1266
1470
|
| `reject-unparseable-signatures` | severity | A broken RBS set **fails the run** instead of degrading it silently: an unparseable `.rbs` under `signature_paths:` (`rbs.coverage.quarantined-signature` → `error`), a declaration that collides on resolve and collapses the whole environment (`rbs.coverage.environment-build-failed` → `error`), and a duplicate method definition that collapses one class's method surface (`rbs.coverage.definition-build-failed` → `error`). |
|
|
1267
1471
|
| `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`). |
|
|
1472
|
+
| `plugin-api-surface` | severity | In plugin source (a class that inherits `Rigor::Plugin::Base`), a call on a `Rigor::Plugin` interface value (a hook's `scope`, `scope.environment`, ...) to a member the interface does not declare is reported as `plugin.api-surface` (`warning`). |
|
|
1268
1473
|
| `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. |
|
|
1269
1474
|
| `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. |
|
|
1270
|
-
| `effects-on-by-default` | behaviour | A project whose `.rigor.yml` carries no [`effects:`](03-configuration.md#effect-labels) key at all is treated as if it had written `effects: {}` — [effect collection](03-configuration.md#effect-labels), the `rigor effects` verbs' cache sharing, and `effects.check` all turn on with every sub-key at its default. Writing `effects: false` explicitly still opts out. **Scheduled to graduate at v0.
|
|
1475
|
+
| `effects-on-by-default` | behaviour | A project whose `.rigor.yml` carries no [`effects:`](03-configuration.md#effect-labels) key at all is treated as if it had written `effects: {}` — [effect collection](03-configuration.md#effect-labels), the `rigor effects` verbs' cache sharing, and `effects.check` all turn on with every sub-key at its default. Writing `effects: false` explicitly still opts out. **Scheduled to graduate at v0.5.0** ([ADR-103](../adr/103-effect-labels.md) § WD15, moved from v0.4.0 by § WD18) rather than at the next major — an owner ruling specific to this feature, ahead of the general v1.0.0 majors-only cadence below. |
|
|
1271
1476
|
|
|
1272
1477
|
Once a feature **graduates** — it becomes the default at a major
|
|
1273
1478
|
([ADR-50](../adr/50-release-engineering-and-stability-strategy.md) § WD7)
|
|
@@ -1352,18 +1557,29 @@ Exits `1` when any check fails, `0` when all pass.
|
|
|
1352
1557
|
|
|
1353
1558
|
## `rigor upgrade`
|
|
1354
1559
|
|
|
1355
|
-
Migration command skeleton ([ADR-50](../adr/50-release-engineering-and-stability-strategy.md)
|
|
1356
|
-
WD7). The real body lands when a concrete backwards-compatibility
|
|
1357
|
-
break gives it a target (e.g. re-running `baseline regenerate`
|
|
1358
|
-
against a strengthened default profile, surfacing renamed
|
|
1359
|
-
suppression ids, reporting `bleeding_edge:` graduations).
|
|
1560
|
+
Migration command skeleton for major version transitions and breaking changes ([ADR-50](../adr/50-release-engineering-and-stability-strategy.md) § WD7).
|
|
1360
1561
|
|
|
1361
1562
|
```sh
|
|
1362
1563
|
rigor upgrade
|
|
1363
1564
|
```
|
|
1364
1565
|
|
|
1365
|
-
|
|
1366
|
-
|
|
1566
|
+
### Design and future role
|
|
1567
|
+
|
|
1568
|
+
The upgrade command is designed to automate project migrations when major version transitions or breaking changes occur:
|
|
1569
|
+
- **Baseline regeneration**: Re-running `rigor baseline regenerate` against strengthened default rules or profiles.
|
|
1570
|
+
- **Suppression updates**: Surfacing and updating renamed or deprecated inline `# rigor:disable` rules.
|
|
1571
|
+
- **Bleeding-edge consolidation**: Reporting and removing graduated features from `bleeding_edge:` configurations.
|
|
1572
|
+
|
|
1573
|
+
### Current status
|
|
1574
|
+
|
|
1575
|
+
Until a backward-incompatible release provides an active migration target, the command serves as a placeholder. It prints the current Rigor version and reports that migrations are queued:
|
|
1576
|
+
|
|
1577
|
+
```text
|
|
1578
|
+
rigor upgrade: No migration target available yet (ADR-50 WD7, queued).
|
|
1579
|
+
Current version: <version>
|
|
1580
|
+
```
|
|
1581
|
+
|
|
1582
|
+
Exit `0` on completion.
|
|
1367
1583
|
|
|
1368
1584
|
## `rigor help`
|
|
1369
1585
|
|
|
@@ -227,12 +227,50 @@ project Ruby's gem home without running your toolchain. If `rigor check`'s
|
|
|
227
227
|
`--stats` shows gems whose RBS it could not find, point it at the bundle
|
|
228
228
|
explicitly with `bundler.bundle_path:`, or supply signatures another way:
|
|
229
229
|
`rbs collection install` (auto-discovered) or `dependencies.source_inference:`.
|
|
230
|
-
| `rbs_collection.auto_detect` | Boolean | `true` | Auto-discover `rbs_collection.lock.yaml`. An entry is not loaded for a gem your `Gemfile.lock` sources from a `path:` directory that is at or under one of your `paths:` entries, or contains one, and is not left out by `exclude:` (the gem is code Rigor analyses, which your `sig/` declares). |
|
|
230
|
+
| `rbs_collection.auto_detect` | Boolean | `true` | Auto-discover `rbs_collection.lock.yaml`. A `source: { type: stdlib }` entry loads that stdlib library, as `libraries:` would. An entry is not loaded for a gem your `Gemfile.lock` sources from a `path:` directory that is at or under one of your `paths:` entries, or contains one, and is not left out by `exclude:` (the gem is code Rigor analyses, which your `sig/` declares). |
|
|
231
231
|
| `rbs_collection.lockfile` | String | `nil` | Explicit `rbs_collection.lock.yaml` path. |
|
|
232
232
|
| `dependencies.source_inference` | Array | `[]` | Per-gem source-inference modes (ADR-10). |
|
|
233
233
|
| `dependencies.budget_per_gem` | Integer | `5000` | Per-gem source-walk cap, counted in **method definitions** (not time): the walker stops harvesting a gem's catalog once it reaches this many `def`s, then emits `dynamic.dependency-source.budget-exceeded` and degrades the rest to `Dynamic[top]`. Range 1250–20000. |
|
|
234
234
|
| `dependencies.budget_overrun_strategy` | String | `"walker_cap"` | What happens to calls on a gem that hit `budget_per_gem` (ADR-10 § 5b). `walker_cap` (default) lets methods past the cap fall through to the engine's normal user-class resolution. `dependency_silence` instead resolves any call on a class from a budget-exceeded gem to `Dynamic[top]`, silencing `call.undefined-method` on that gem's unrecorded surface at the cost of weaker static checking there. |
|
|
235
235
|
|
|
236
|
+
#### Running Rigor in a gem_rbs_collection `_test/` directory
|
|
237
|
+
|
|
238
|
+
To check a signature you are writing for
|
|
239
|
+
[`ruby/gem_rbs_collection`](https://github.com/ruby/gem_rbs_collection), run
|
|
240
|
+
Rigor in the gem's `gems/<name>/<version>/_test/` directory after the
|
|
241
|
+
collection's own test setup:
|
|
242
|
+
|
|
243
|
+
1. Run `bin/test gems/<name>/<version>` once from the collection root. It
|
|
244
|
+
writes `rbs_collection.yaml` and `rbs_collection.lock.yaml` into `_test/`
|
|
245
|
+
and installs the gem and its dependencies into `_test/.gem_rbs_collection/`,
|
|
246
|
+
with your working tree linked in as a `local` source.
|
|
247
|
+
2. Put a `.rigor.yml` in `_test/`:
|
|
248
|
+
|
|
249
|
+
```yaml
|
|
250
|
+
paths: ["."]
|
|
251
|
+
signature_paths: ["."]
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
This is the shape of the `Steepfile` that `bin/test` writes (`check "."`,
|
|
255
|
+
`signature "."`). Rigor finds the lockfile and loads the gem and its
|
|
256
|
+
dependencies from it, and `signature_paths: ["."]` loads the `.rbs` files in
|
|
257
|
+
`_test/` itself. Without that line, the types those test signatures declare
|
|
258
|
+
are absent and calls into them are not checked.
|
|
259
|
+
|
|
260
|
+
`signature_paths: [".."]` is also safe. It loads the gem from your working
|
|
261
|
+
tree, and Rigor skips the lockfile's copy of the same gem and version, so the
|
|
262
|
+
gem is not loaded twice. Use it when the lockfile's copy is not your working
|
|
263
|
+
tree, for example when `rbs_collection.yaml` names a `git` source instead of
|
|
264
|
+
the collection's `gems/` directory.
|
|
265
|
+
3. Run `rigor check` in `_test/`.
|
|
266
|
+
|
|
267
|
+
Rigor skips every `_`-prefixed directory inside a collected gem, such as another
|
|
268
|
+
gem's `_test/` fixtures, as `rbs` does. Rigor does not read `manifest.yaml`
|
|
269
|
+
or a gemspec to find dependencies. Without a lockfile it loads none of them and
|
|
270
|
+
reports `rbs.coverage.collection-not-installed` (`:info`), which tells you to run
|
|
271
|
+
the `bin/test` setup, or `rbs collection install` where an `rbs_collection.yaml`
|
|
272
|
+
is present.
|
|
273
|
+
|
|
236
274
|
### Execution
|
|
237
275
|
|
|
238
276
|
| Key | Type | Default | Meaning |
|
|
@@ -270,8 +308,8 @@ config with no `effects:` key at all behave as `effects: {}` — collection,
|
|
|
270
308
|
`effects.check`, and everything else on this page all turn on at their
|
|
271
309
|
defaults. It only fills an *absence*: write `effects: false` and you stay
|
|
272
310
|
opted out regardless, and any `effects:` block you do write is left exactly
|
|
273
|
-
as written. It previews what becomes the default at **v0.
|
|
274
|
-
([ADR-103](../adr/103-effect-labels.md) § WD15).
|
|
311
|
+
as written. It previews what becomes the default at **v0.5.0**
|
|
312
|
+
([ADR-103](../adr/103-effect-labels.md) § WD15, moved by § WD18).
|
|
275
313
|
|
|
276
314
|
#### Entry-point presets
|
|
277
315
|
|