rigortype 0.4.6 → 0.4.7
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 +2 -2
- data/data/gem_overlay/activesupport/core_ext.rbs +16 -13
- data/data/vendored_gem_sigs/bundler/bundler.rbs +1 -1
- data/data/vendored_gem_sigs/rubygems/rubygems_extras.rbs +4 -3
- data/docs/handbook/01-getting-started.md +5 -2
- data/docs/handbook/11-sig-gen.md +50 -3
- data/docs/handbook/appendix-phpstan.md +4 -4
- data/docs/manual/02-cli-reference.md +152 -26
- data/docs/manual/03-configuration.md +36 -3
- data/docs/manual/06-baseline.md +6 -4
- data/docs/manual/09-editor-integration.md +13 -2
- data/docs/manual/10-mcp-server.md +38 -2
- data/docs/manual/12-caching.md +4 -3
- data/docs/manual/plugins/rigor-actionpack.md +19 -11
- data/docs/manual/plugins/rigor-activesupport-core-ext.md +20 -1
- data/lib/rigor/analysis/baseline.rb +24 -27
- data/lib/rigor/analysis/check_rules/always_truthy_condition_collector.rb +5 -6
- data/lib/rigor/analysis/check_rules/dead_assignment_collector.rb +2 -2
- data/lib/rigor/analysis/check_rules/declaration_sourced_guard.rb +4 -4
- data/lib/rigor/analysis/check_rules/duplicate_hash_key_collector.rb +2 -2
- data/lib/rigor/analysis/check_rules/inferred_param_guard.rb +85 -13
- data/lib/rigor/analysis/check_rules/ivar_write_collector.rb +3 -2
- data/lib/rigor/analysis/check_rules/lexical_method_sites.rb +0 -1
- data/lib/rigor/analysis/check_rules/main_pass_collector.rb +5 -8
- data/lib/rigor/analysis/check_rules/published_constant_guard.rb +1 -1
- data/lib/rigor/analysis/check_rules/rebinding_block_callees.rb +3 -3
- data/lib/rigor/analysis/check_rules/return_in_ensure_collector.rb +1 -2
- data/lib/rigor/analysis/check_rules/rule_ids.rb +1 -1
- data/lib/rigor/analysis/check_rules/rule_walk.rb +9 -7
- data/lib/rigor/analysis/check_rules/shadowed_rescue_collector.rb +3 -4
- data/lib/rigor/analysis/check_rules/special_global_setters.rb +3 -3
- data/lib/rigor/analysis/check_rules/unreachable_clause_collector.rb +2 -2
- data/lib/rigor/analysis/check_rules/void_value_use_collector.rb +1 -1
- data/lib/rigor/analysis/check_rules.rb +124 -44
- data/lib/rigor/analysis/crash_signature.rb +2 -2
- data/lib/rigor/analysis/dependency_recorder.rb +4 -4
- data/lib/rigor/analysis/dependency_source_inference/boundary_cross_reporter.rb +14 -3
- data/lib/rigor/analysis/dependency_source_inference/gem_resolver.rb +1 -1
- data/lib/rigor/analysis/dependency_source_inference/index.rb +6 -8
- data/lib/rigor/analysis/dependency_source_inference/walker.rb +4 -4
- data/lib/rigor/analysis/edit_replay.rb +93 -6
- data/lib/rigor/analysis/fact_store.rb +3 -3
- data/lib/rigor/analysis/incremental_run_slot/write_guard.rb +2 -2
- data/lib/rigor/analysis/incremental_run_slot.rb +2 -2
- data/lib/rigor/analysis/incremental_session.rb +27 -16
- data/lib/rigor/analysis/rule_catalog.rb +2 -2
- data/lib/rigor/analysis/run_stats.rb +2 -2
- data/lib/rigor/analysis/runner/buffer_pool_dispatcher.rb +2 -2
- data/lib/rigor/analysis/runner/declaration_position.rb +1 -1
- data/lib/rigor/analysis/runner/diagnostic_aggregator.rb +193 -93
- data/lib/rigor/analysis/runner/effect_envelope_pass.rb +1 -1
- data/lib/rigor/analysis/runner/pool_coordinator.rb +147 -323
- data/lib/rigor/analysis/runner/project_pre_passes.rb +3 -3
- data/lib/rigor/analysis/runner/run_level_facts.rb +304 -0
- data/lib/rigor/analysis/runner/run_snapshots.rb +44 -54
- data/lib/rigor/analysis/runner/worker_payload.rb +36 -0
- data/lib/rigor/analysis/runner.rb +77 -71
- data/lib/rigor/analysis/self_call_resolution_recorder.rb +1 -1
- data/lib/rigor/analysis/template_unit_positions.rb +2 -3
- data/lib/rigor/analysis/template_units.rb +9 -1
- data/lib/rigor/analysis/worker_session.rb +24 -31
- data/lib/rigor/bleeding_edge.rb +3 -6
- data/lib/rigor/builtins/imported_refinements.rb +6 -8
- data/lib/rigor/builtins/predefined_constant_refinements.rb +1 -1
- data/lib/rigor/builtins/regex_refinement.rb +4 -6
- data/lib/rigor/cache/descriptor.rb +6 -5
- data/lib/rigor/cache/incremental_snapshot.rb +31 -12
- data/lib/rigor/cache/rbs_cache_producer.rb +2 -2
- data/lib/rigor/cache/rbs_class_ancestor_table.rb +1 -1
- data/lib/rigor/cache/rbs_class_type_param_names.rb +2 -2
- data/lib/rigor/cache/rbs_constant_table.rb +1 -1
- data/lib/rigor/cache/rbs_descriptor.rb +54 -3
- data/lib/rigor/cache/rbs_environment.rb +4 -1
- data/lib/rigor/cache/rbs_environment_marshal_patch.rb +2 -2
- data/lib/rigor/cache/rbs_known_class_names.rb +1 -1
- data/lib/rigor/cache/store.rb +11 -10
- data/lib/rigor/ci_detector.rb +1 -1
- data/lib/rigor/cli/annotate_command.rb +24 -19
- data/lib/rigor/cli/baseline_command.rb +145 -55
- data/lib/rigor/cli/catalogue.rb +256 -0
- data/lib/rigor/cli/check_command.rb +108 -102
- data/lib/rigor/cli/check_runner_factory.rb +2 -2
- data/lib/rigor/cli/command.rb +15 -1
- data/lib/rigor/cli/coverage_command.rb +21 -8
- data/lib/rigor/cli/coverage_mutation.rb +5 -7
- data/lib/rigor/cli/coverage_renderer.rb +2 -1
- data/lib/rigor/cli/coverage_scan.rb +3 -5
- data/lib/rigor/cli/diff_command.rb +25 -20
- data/lib/rigor/cli/docs_command.rb +1 -2
- data/lib/rigor/cli/doctor_command.rb +12 -12
- data/lib/rigor/cli/effects_command.rb +50 -40
- data/lib/rigor/cli/effects_diff_renderer.rb +18 -17
- data/lib/rigor/cli/effects_explain_renderer.rb +13 -12
- data/lib/rigor/cli/effects_renderer.rb +2 -1
- data/lib/rigor/cli/effects_snapshot_command.rb +18 -17
- data/lib/rigor/cli/explain_command.rb +18 -8
- data/lib/rigor/cli/fused_protection_renderer.rb +2 -1
- data/lib/rigor/cli/json_document.rb +41 -0
- data/lib/rigor/cli/lens_command.rb +12 -8
- data/lib/rigor/cli/lsp_command.rb +250 -23
- data/lib/rigor/cli/mcp_command.rb +12 -7
- data/lib/rigor/cli/mutation_fork_scan.rb +1 -1
- data/lib/rigor/cli/mutation_protection_renderer.rb +3 -2
- data/lib/rigor/cli/options.rb +40 -1
- data/lib/rigor/cli/plugin_command.rb +93 -46
- data/lib/rigor/cli/plugins_command.rb +17 -18
- data/lib/rigor/cli/plugins_renderer.rb +10 -6
- data/lib/rigor/cli/protection_fork_scan.rb +2 -2
- data/lib/rigor/cli/protection_renderer.rb +2 -1
- data/lib/rigor/cli/show_bleedingedge_command.rb +21 -15
- data/lib/rigor/cli/sig_gen_command.rb +84 -27
- data/lib/rigor/cli/skill_command.rb +32 -3
- data/lib/rigor/cli/skill_deep_probe.rb +1 -1
- data/lib/rigor/cli/skill_describe.rb +1 -1
- data/lib/rigor/cli/trace_command.rb +14 -9
- data/lib/rigor/cli/triage_command.rb +10 -11
- data/lib/rigor/cli/triage_renderer.rb +2 -1
- data/lib/rigor/cli/type_of_command.rb +16 -11
- data/lib/rigor/cli/type_of_project_scope.rb +1 -4
- data/lib/rigor/cli/type_of_renderer.rb +4 -1
- data/lib/rigor/cli/type_scan_command.rb +14 -9
- data/lib/rigor/cli/type_scan_renderer.rb +2 -1
- data/lib/rigor/cli/unused_command.rb +27 -17
- data/lib/rigor/cli/upgrade_command.rb +5 -0
- data/lib/rigor/cli.rb +209 -54
- data/lib/rigor/config_audit.rb +1 -1
- data/lib/rigor/configuration/severity_profile.rb +5 -5
- data/lib/rigor/configuration.rb +72 -30
- data/lib/rigor/effects/definition_context.rb +0 -2
- data/lib/rigor/effects/envelope.rb +1 -1
- data/lib/rigor/effects/framework_units.rb +1 -1
- data/lib/rigor/effects/mutation_classifier.rb +4 -7
- data/lib/rigor/effects/propagator.rb +1 -1
- data/lib/rigor/effects/registry.rb +2 -2
- data/lib/rigor/effects/snapshot.rb +1 -1
- data/lib/rigor/effects/taint_cause.rb +0 -2
- data/lib/rigor/effects/unit_scan.rb +9 -13
- data/lib/rigor/environment/bundle_sig_discovery.rb +5 -9
- data/lib/rigor/environment/class_registry.rb +3 -3
- data/lib/rigor/environment/core_root.rb +77 -0
- data/lib/rigor/environment/default_libraries.rb +1 -1
- data/lib/rigor/environment/deferred_signature_plan.rb +283 -0
- data/lib/rigor/environment/gated_signature_guard.rb +1 -1
- data/lib/rigor/environment/gated_signature_plan.rb +5 -2
- data/lib/rigor/environment/lockfile_resolver.rb +28 -12
- data/lib/rigor/environment/member_consistency/comparator.rb +18 -1
- data/lib/rigor/environment/member_consistency.rb +56 -7
- data/lib/rigor/environment/missing_gem_constant_index.rb +3 -2
- data/lib/rigor/environment/project_path_gems.rb +124 -0
- data/lib/rigor/environment/rbs_hierarchy.rb +6 -15
- data/lib/rigor/environment/rbs_loader.rb +480 -67
- data/lib/rigor/environment/reflection.rb +7 -7
- data/lib/rigor/environment/required_features.rb +0 -3
- data/lib/rigor/environment/ruby_library_roots.rb +1 -1
- data/lib/rigor/environment/vendored_signature_plan.rb +153 -0
- data/lib/rigor/environment.rb +41 -10
- data/lib/rigor/flow_contribution/merger.rb +4 -4
- data/lib/rigor/inference/acceptance.rb +93 -32
- data/lib/rigor/inference/block_parameter_binder.rb +2 -3
- data/lib/rigor/inference/block_run_count.rb +178 -0
- data/lib/rigor/inference/budget_trace.rb +8 -2
- data/lib/rigor/inference/builtins/exception_catalog.rb +2 -2
- data/lib/rigor/inference/builtins/numeric_catalog.rb +2 -5
- data/lib/rigor/inference/builtins/random_catalog.rb +2 -2
- data/lib/rigor/inference/callee_mutation_chain.rb +88 -77
- data/lib/rigor/inference/callee_write_census.rb +815 -0
- data/lib/rigor/inference/construction_escape.rb +217 -0
- data/lib/rigor/inference/declaration_walk/traversal.rb +1 -1
- data/lib/rigor/inference/deep_erasure.rb +39 -7
- data/lib/rigor/inference/def_handle.rb +1 -1
- data/lib/rigor/inference/def_node_resolver.rb +1 -1
- data/lib/rigor/inference/def_return_typer.rb +46 -4
- data/lib/rigor/inference/definer_resolution.rb +4 -2
- data/lib/rigor/inference/definers_index.rb +106 -0
- data/lib/rigor/inference/direct_ivar_writes.rb +300 -0
- data/lib/rigor/inference/element_read_widening.rb +49 -3
- data/lib/rigor/inference/expression_typer.rb +116 -49
- data/lib/rigor/inference/external_ancestor_resolution.rb +3 -4
- data/lib/rigor/inference/global_write_census.rb +76 -2
- data/lib/rigor/inference/global_writer_reach.rb +260 -0
- data/lib/rigor/inference/hkt_body.rb +1 -2
- data/lib/rigor/inference/hkt_body_parser.rb +3 -5
- data/lib/rigor/inference/hkt_reducer.rb +2 -2
- data/lib/rigor/inference/hkt_registry.rb +3 -5
- data/lib/rigor/inference/indexed_narrowing.rb +4 -7
- data/lib/rigor/inference/intervening_ivar_reset.rb +26 -4
- data/lib/rigor/inference/ivar_writer_census.rb +51 -0
- data/lib/rigor/inference/key_presence_guard.rb +2 -1
- data/lib/rigor/inference/loop_value_record.rb +8 -4
- data/lib/rigor/inference/match_rebinding/frame.rb +46 -0
- data/lib/rigor/inference/match_rebinding/yielding_match.rb +45 -0
- data/lib/rigor/inference/match_rebinding.rb +11 -1
- data/lib/rigor/inference/memo_audit.rb +55 -0
- data/lib/rigor/inference/method_dispatcher/alias_strict_nominals.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/argument_distribution.rb +40 -0
- data/lib/rigor/inference/method_dispatcher/block_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/constant_folding.rb +3 -3
- data/lib/rigor/inference/method_dispatcher/contested_overloads.rb +89 -0
- data/lib/rigor/inference/method_dispatcher/iterator_dispatch.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/kernel_dispatch.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/no_match_fallback.rb +54 -0
- data/lib/rigor/inference/method_dispatcher/overload_selector.rb +39 -27
- data/lib/rigor/inference/method_dispatcher/random_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/rbs_dispatch.rb +203 -17
- data/lib/rigor/inference/method_dispatcher/reduce_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/regexp_folding.rb +2 -2
- data/lib/rigor/inference/method_dispatcher/self_substitute.rb +2 -2
- data/lib/rigor/inference/method_dispatcher/set_folding.rb +9 -7
- data/lib/rigor/inference/method_dispatcher/shape_dispatch.rb +83 -20
- data/lib/rigor/inference/method_dispatcher/singleton_folding.rb +0 -1
- data/lib/rigor/inference/method_dispatcher/singleton_mixin_dispatch.rb +50 -17
- data/lib/rigor/inference/method_dispatcher/struct_folding.rb +5 -5
- data/lib/rigor/inference/method_dispatcher/struct_materialization.rb +4 -6
- data/lib/rigor/inference/method_dispatcher/uri_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher.rb +64 -14
- data/lib/rigor/inference/module_function_state.rb +11 -1
- data/lib/rigor/inference/multi_target_binder.rb +1 -1
- data/lib/rigor/inference/mutation_rejoin.rb +240 -4
- data/lib/rigor/inference/mutation_widening.rb +157 -27
- data/lib/rigor/inference/narrowing.rb +47 -33
- data/lib/rigor/inference/optimistic_origin.rb +1 -1
- data/lib/rigor/inference/out_buffer_mutation.rb +72 -0
- data/lib/rigor/inference/parameter_inference_collector.rb +5 -6
- data/lib/rigor/inference/pre_eval_constants.rb +1 -1
- data/lib/rigor/inference/project_method_ownership.rb +6 -3
- data/lib/rigor/inference/project_yielder.rb +11 -17
- data/lib/rigor/inference/receiver_alias.rb +20 -0
- data/lib/rigor/inference/refined_dispatch/constructed_class.rb +3 -1
- data/lib/rigor/inference/refined_dispatch/own_method.rb +2 -1
- data/lib/rigor/inference/remover_holder_scan.rb +233 -0
- data/lib/rigor/inference/remover_narrowing.rb +224 -0
- data/lib/rigor/inference/rewrite_mutation.rb +53 -2
- data/lib/rigor/inference/scope_indexer/certainty.rb +0 -1
- data/lib/rigor/inference/scope_indexer/constant_ivar_value.rb +93 -0
- data/lib/rigor/inference/scope_indexer/declared_param_writes.rb +58 -15
- data/lib/rigor/inference/scope_indexer/derived_param_value.rb +112 -0
- data/lib/rigor/inference/scope_indexer/empty_seed.rb +99 -0
- data/lib/rigor/inference/scope_indexer/ivar_contributions.rb +135 -0
- data/lib/rigor/inference/scope_indexer.rb +137 -46
- data/lib/rigor/inference/self_call_ivar_writes.rb +84 -12
- data/lib/rigor/inference/set_mutation.rb +189 -0
- data/lib/rigor/inference/singleton_hook_decline.rb +1 -2
- data/lib/rigor/inference/statement_evaluator.rb +2328 -138
- data/lib/rigor/inference/struct_fold_safety.rb +4 -6
- data/lib/rigor/inference/synthetic_method_scanner.rb +5 -6
- data/lib/rigor/inference/toplevel_def_census.rb +59 -0
- data/lib/rigor/inference/unknown_store_widening.rb +103 -4
- data/lib/rigor/inference/unthreaded_rebinds.rb +2 -3
- data/lib/rigor/inference/void_tail_summary.rb +2 -1
- data/lib/rigor/language_server/buffer_table.rb +3 -3
- data/lib/rigor/language_server/completion_provider.rb +26 -20
- data/lib/rigor/language_server/config_warning_announcer.rb +28 -0
- data/lib/rigor/language_server/diagnostic_publisher.rb +8 -3
- data/lib/rigor/language_server/document_symbol_provider.rb +1 -1
- data/lib/rigor/language_server/folding_range_provider.rb +1 -2
- data/lib/rigor/language_server/hover_provider.rb +1 -7
- data/lib/rigor/language_server/hover_renderer.rb +6 -8
- data/lib/rigor/language_server/project_context.rb +39 -1
- data/lib/rigor/language_server/publish_batcher.rb +3 -4
- data/lib/rigor/language_server/selection_range_provider.rb +2 -4
- data/lib/rigor/language_server/server.rb +7 -3
- data/lib/rigor/language_server/signature_help_provider.rb +4 -4
- data/lib/rigor/lens/plugins.rb +1 -1
- data/lib/rigor/mcp/server.rb +73 -2
- data/lib/rigor/mcp.rb +1 -1
- data/lib/rigor/plugin/access_denied_error.rb +1 -2
- data/lib/rigor/plugin/bundled_catalog.rb +1 -12
- data/lib/rigor/plugin/io_boundary.rb +1 -1
- data/lib/rigor/plugin/loader.rb +25 -8
- data/lib/rigor/plugin/macro/heredoc_template.rb +7 -8
- data/lib/rigor/plugin/macro/trait_registry.rb +6 -9
- data/lib/rigor/plugin/manifest.rb +9 -13
- data/lib/rigor/plugin/registry.rb +3 -3
- data/lib/rigor/plugin/services.rb +2 -3
- data/lib/rigor/plugin/source_rbs_synthesis_reporter.rb +11 -0
- data/lib/rigor/plugin/trust_policy.rb +2 -2
- data/lib/rigor/plugin/type_node_resolver.rb +2 -4
- data/lib/rigor/plugin.rb +6 -8
- data/lib/rigor/plugin_gap_advisory.rb +5 -1
- data/lib/rigor/project_environment.rb +16 -2
- data/lib/rigor/protection/analysis_guard.rb +1 -1
- data/lib/rigor/protection/discovery_seed.rb +44 -5
- data/lib/rigor/protection/mutator.rb +1 -1
- data/lib/rigor/rbs_extended/envelope_scanner.rb +4 -6
- data/lib/rigor/rbs_extended/hkt_directives.rb +6 -10
- data/lib/rigor/rbs_extended/reporter.rb +27 -3
- data/lib/rigor/rbs_extended.rb +2 -3
- data/lib/rigor/reflection/constant_ancestors.rb +5 -3
- data/lib/rigor/rooted_glob.rb +15 -1
- data/lib/rigor/run_scoped_slots.rb +38 -0
- data/lib/rigor/runtime/jit.rb +1 -1
- data/lib/rigor/scope/discovery_index.rb +19 -6
- data/lib/rigor/scope/resolution_chain.rb +3 -1
- data/lib/rigor/scope.rb +365 -31
- data/lib/rigor/sig_gen/classification.rb +4 -0
- data/lib/rigor/sig_gen/effect_annotation.rb +3 -3
- data/lib/rigor/sig_gen/generator.rb +371 -58
- data/lib/rigor/sig_gen/generic_header_scan.rb +189 -0
- data/lib/rigor/sig_gen/inline_declarations.rb +2 -2
- data/lib/rigor/sig_gen/layout_index.rb +3 -3
- data/lib/rigor/sig_gen/method_candidate.rb +23 -4
- data/lib/rigor/sig_gen/observation_collector.rb +3 -5
- data/lib/rigor/sig_gen/observed_call.rb +1 -1
- data/lib/rigor/sig_gen/path_mapper.rb +6 -0
- data/lib/rigor/sig_gen/renderer.rb +15 -9
- data/lib/rigor/sig_gen/skip_reason_catalog.rb +15 -2
- data/lib/rigor/sig_gen/type_name_qualification.rb +69 -0
- data/lib/rigor/sig_gen/write_reporter.rb +63 -14
- data/lib/rigor/sig_gen/write_result.rb +23 -12
- data/lib/rigor/sig_gen/writer.rb +217 -37
- data/lib/rigor/type/acceptance_router.rb +2 -2
- data/lib/rigor/type/accepts_result.rb +1 -1
- data/lib/rigor/type/app.rb +4 -6
- data/lib/rigor/type/combinator.rb +9 -13
- data/lib/rigor/type/constant.rb +4 -5
- data/lib/rigor/type/hash_shape.rb +21 -40
- data/lib/rigor/type/union.rb +1 -1
- data/lib/rigor/type_node/identifier.rb +1 -2
- data/lib/rigor/type_node/resolver_chain.rb +1 -1
- data/lib/rigor/type_node/string_literal.rb +1 -2
- data/lib/rigor/type_node/symbol_literal.rb +1 -2
- data/lib/rigor/type_node/union.rb +3 -6
- data/lib/rigor/value_semantics.rb +1 -10
- data/lib/rigor/version.rb +1 -1
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_discoverer.rb +2 -2
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_index.rb +2 -3
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable.rb +1 -1
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_discoverer.rb +38 -36
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_index.rb +4 -2
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer.rb +6 -4
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/analyzer.rb +1 -1
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_index.rb +1 -5
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_scan.rb +0 -1
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/erb_compiler.rb +2 -1
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/view_assigns.rb +1 -1
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack.rb +66 -19
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/effects.rb +1 -1
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob.rb +4 -3
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/association_roots.rb +3 -2
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/effects.rb +2 -2
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_discoverer.rb +21 -31
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_index.rb +10 -16
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_parser.rb +2 -3
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_table.rb +0 -1
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord.rb +5 -4
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/attachment_discoverer.rb +3 -4
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/attachment_index.rb +1 -1
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage.rb +7 -12
- data/plugins/rigor-activestorage/lib/rigor-activestorage.rb +1 -1
- data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext/effects.rb +1 -1
- data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext/symbolize_keys.rb +102 -0
- data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext.rb +19 -6
- data/plugins/rigor-activesupport-core-ext/sig/active_support/core_ext.rbs +26 -13
- data/plugins/rigor-alba/lib/rigor/plugin/alba/resource_index.rb +3 -3
- data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema/schema_scanner.rb +1 -3
- data/plugins/rigor-dry-struct/lib/rigor/plugin/dry_struct.rb +6 -6
- data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types/alias_scanner.rb +5 -6
- data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types.rb +1 -1
- data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation/params_shape.rb +2 -3
- data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation.rb +5 -8
- data/plugins/rigor-ethon/lib/rigor/plugin/ethon.rb +0 -1
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_discoverer.rb +1 -1
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot.rb +10 -18
- data/plugins/rigor-ffi/lib/rigor/plugin/ffi/analyzer.rb +0 -1
- data/plugins/rigor-ffi/lib/rigor/plugin/ffi/discoverer.rb +0 -2
- data/plugins/rigor-ffi/lib/rigor/plugin/ffi.rb +4 -5
- data/plugins/rigor-grape/lib/rigor/plugin/grape.rb +0 -2
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql/type_scanner.rb +6 -7
- data/plugins/rigor-hanami/lib/rigor/plugin/hanami/action_checker.rb +2 -4
- data/plugins/rigor-hanami/lib/rigor/plugin/hanami.rb +2 -5
- data/plugins/rigor-mangrove/lib/rigor/plugin/mangrove.rb +2 -2
- data/plugins/rigor-minitest/lib/rigor/plugin/minitest/assertion_analyzer.rb +6 -6
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_discoverer.rb +2 -1
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/analyzer.rb +3 -8
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_index.rb +2 -3
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_loader.rb +5 -8
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/analyzer.rb +1 -3
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/devise_routes.rb +2 -3
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_discoverer.rb +1 -1
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/routes_parser.rb +4 -11
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes.rb +1 -1
- data/plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline.rb +2 -1
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/matcher_analyzer.rb +1 -1
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec.rb +2 -2
- data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails.rb +3 -4
- data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers/analyzer.rb +6 -8
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq.rb +3 -2
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/absurd_recognizer.rb +4 -5
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/assertion_recognizer.rb +6 -7
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog.rb +1 -1
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sig_parser.rb +2 -2
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet.rb +17 -21
- data/plugins/rigor-statesman/lib/rigor/plugin/statesman.rb +2 -3
- data/plugins/rigor-typelizer/lib/rigor/plugin/typelizer/serializer_discoverer.rb +3 -2
- data/plugins/rigor-typelizer/lib/rigor/plugin/typelizer/serializer_index.rb +4 -4
- data/sig/rigor/analysis/baseline.rbs +0 -3
- data/sig/rigor/analysis/fact_store.rbs +1 -0
- data/sig/rigor/analysis/reachability/scan_cache.rbs +1 -1
- data/sig/rigor/cli/diff_command.rbs +1 -1
- data/sig/rigor/cli/explain_command.rbs +1 -1
- data/sig/rigor/effects/registry.rbs +2 -2
- data/sig/rigor/inference.rbs +4 -1
- data/sig/rigor/plugin/additional_initializer.rbs +0 -5
- data/sig/rigor/plugin/base.rbs +1 -0
- data/sig/rigor/plugin/effect_attribution.rbs +3 -3
- data/sig/rigor/plugin/effect_edge.rbs +1 -1
- data/sig/rigor/plugin/effect_entry_points.rbs +3 -3
- data/sig/rigor/plugin/io_boundary.rbs +2 -1
- data/sig/rigor/plugin/manifest.rbs +9 -9
- data/sig/rigor/plugin/protocol_contract.rbs +3 -7
- data/sig/rigor/scope.rbs +23 -3
- data/skills/rigor-plugin-author/SKILL.md +4 -4
- data/skills/rigor-plugin-author/references/02-walker-and-types.md +5 -5
- data/skills/rigor-plugin-review/SKILL.md +3 -3
- data/skills/rigor-project-init/references/03-baseline-and-bugs.md +12 -1
- metadata +36 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 983cf341f34d4407d6d06ab2b0bf50260f5b52a4f6e29c61ce0042123ab833cc
|
|
4
|
+
data.tar.gz: 17ea6b8b13033e507d0e7570913ab2609c830c9a5cfa706cfe055b6857d315f5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0cd85174733cb61860d33f5636e81ac5d19972f9e6bd66fc6282d1aa7330735f8a57a067e1cfa81071632a45a0ca123f607be5b5bda7b3b32153fb8069328dfc
|
|
7
|
+
data.tar.gz: 64ecfde3bfe3eaef83ff44fa6ee1ca72bf6f353648c55a354726e60a87203012f907ce5406dc162289ff2a99056cf8b2962a79f636d5e7dd93cf16ec2b00e8d2
|
data/README.md
CHANGED
|
@@ -131,7 +131,7 @@ and [CI guide](https://rigor.typedduck.fail/manual/11-ci/).
|
|
|
131
131
|
|
|
132
132
|
```sh
|
|
133
133
|
rigor check lib # find bugs (caches under .rigor/ — gitignore it)
|
|
134
|
-
rigor init # drop a starter .rigor.yml
|
|
134
|
+
rigor init # drop a starter .rigor.yml (suggests plugins from Gemfile.lock)
|
|
135
135
|
rigor annotate lib/foo.rb # reprint a file with inferred types in the margin
|
|
136
136
|
rigor triage lib # summarise diagnostics: distribution, hotspots
|
|
137
137
|
rigor sig-gen --diff lib/foo.rb # emit RBS from inference (--write to save)
|
|
@@ -232,7 +232,7 @@ rigor docs --list # list every bundled page
|
|
|
232
232
|
|
|
233
233
|
## Status
|
|
234
234
|
|
|
235
|
-
Current release: **`v0.4.
|
|
235
|
+
Current release: **`v0.4.7`** (2026-11-03) — on the
|
|
236
236
|
`0.4.x` line, continuing the evaluation era opened by `v0.2.0`, the first
|
|
237
237
|
publicly-announced (general / evaluation) release. The line publishes
|
|
238
238
|
an enumerated [compatibility surface](docs/compatibility.md) as a
|
|
@@ -898,31 +898,34 @@ end
|
|
|
898
898
|
|
|
899
899
|
class Hash[unchecked out K, unchecked out V]
|
|
900
900
|
# `core_ext/hash/keys`
|
|
901
|
-
|
|
901
|
+
# `key.to_sym rescue key` keeps a key without `to_sym`, so no one key type is right: `Hash[untyped, V]` here,
|
|
902
|
+
# and with the plugin `dynamic_return` hook (#2433) maps each key member where it can.
|
|
903
|
+
def symbolize_keys: () -> Hash[untyped, V]
|
|
902
904
|
def symbolize_keys!: () -> self
|
|
903
905
|
def deep_symbolize_keys: () -> Hash[untyped, untyped]
|
|
904
|
-
def deep_symbolize_keys!: () ->
|
|
906
|
+
def deep_symbolize_keys!: () -> Hash[untyped, untyped]
|
|
905
907
|
def stringify_keys: () -> Hash[String, V]
|
|
906
|
-
def stringify_keys!: () ->
|
|
908
|
+
def stringify_keys!: () -> Hash[String, V]
|
|
907
909
|
def deep_stringify_keys: () -> Hash[untyped, untyped]
|
|
908
|
-
def deep_stringify_keys!: () ->
|
|
910
|
+
def deep_stringify_keys!: () -> Hash[untyped, untyped]
|
|
909
911
|
def assert_valid_keys: (*K | Array[K]) -> self
|
|
910
|
-
def deep_transform_keys: () { (K) ->
|
|
911
|
-
def deep_transform_keys!: () { (K) ->
|
|
912
|
+
def deep_transform_keys: [X] () { (K) -> X } -> Hash[X, untyped]
|
|
913
|
+
def deep_transform_keys!: [X] () { (K) -> X } -> Hash[X, untyped]
|
|
912
914
|
def deep_transform_values: () { (V) -> untyped } -> Hash[K, untyped]
|
|
913
|
-
def deep_transform_values!: () { (V) -> untyped } ->
|
|
915
|
+
def deep_transform_values!: () { (V) -> untyped } -> Hash[K, untyped]
|
|
914
916
|
# `alias_method`s of `symbolize_keys` / `symbolize_keys!`.
|
|
915
|
-
def to_options: () -> Hash[
|
|
917
|
+
def to_options: () -> Hash[untyped, V]
|
|
916
918
|
def to_options!: () -> self
|
|
917
919
|
|
|
918
920
|
# `core_ext/hash/deep_dup`
|
|
919
921
|
def deep_dup: () -> Hash[K, V]
|
|
920
922
|
|
|
921
|
-
# `core_ext/hash/deep_merge`
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
923
|
+
# `core_ext/hash/deep_merge` — the twin of the plugin's rows (#2424 review): the argument's keys join the
|
|
924
|
+
# receiver's, and a nested merge makes a value neither side declares, so values read `untyped`.
|
|
925
|
+
def deep_merge: [A, B] (Hash[A, B] other_hash) -> Hash[K | A, untyped]
|
|
926
|
+
| [A, B] (Hash[A, B] other_hash) { (K | A, untyped, untyped) -> untyped } -> Hash[K | A, untyped]
|
|
927
|
+
def deep_merge!: [A, B] (Hash[A, B] other_hash) -> Hash[K | A, untyped]
|
|
928
|
+
| [A, B] (Hash[A, B] other_hash) { (K | A, untyped, untyped) -> untyped } -> Hash[K | A, untyped]
|
|
926
929
|
# `other.is_a?(Hash)` — the hook `ActiveSupport::DeepMergeable` asks before
|
|
927
930
|
# recursing into a value. `:nodoc:`, but public.
|
|
928
931
|
def deep_merge?: (untyped other) -> bool
|
|
@@ -150,7 +150,7 @@ module Bundler
|
|
|
150
150
|
# `#initialize`, `#specs` — declared by `sig/shims/bundler.rbs` with the same types.
|
|
151
151
|
def platforms: () -> Array[untyped]
|
|
152
152
|
def sources: () -> Array[untyped]
|
|
153
|
-
def dependencies: () ->
|
|
153
|
+
def dependencies: () -> Hash[String, Dependency]
|
|
154
154
|
def ruby_version: () -> untyped
|
|
155
155
|
def bundler_version: () -> untyped
|
|
156
156
|
end
|
|
@@ -112,8 +112,9 @@ class Gem::Specification
|
|
|
112
112
|
|
|
113
113
|
# Instance-side surface widely used by bundler / rubygems
|
|
114
114
|
# internals. `attr_accessor` mirrors the writer + reader pair
|
|
115
|
-
# so the survey's `.name=` / `.version=` / `.
|
|
116
|
-
# `.
|
|
115
|
+
# so the survey's `.name=` / `.version=` / `.loaded_from=` /
|
|
116
|
+
# `.post_install_message=` writes resolve too. `.full_gem_path` is declared on `Gem::BasicSpecification`,
|
|
117
|
+
# which this class inherits from.
|
|
117
118
|
def activate: () -> untyped
|
|
118
119
|
def specification_version: () -> Integer
|
|
119
120
|
def files: () -> Array[String]
|
|
@@ -127,13 +128,13 @@ class Gem::Specification
|
|
|
127
128
|
# `#version`'s READER is declared by `sig/shims/rubygems.rbs` (`attr_reader version (): Version`);
|
|
128
129
|
# only the writer is ours.
|
|
129
130
|
def version=: (Gem::Version) -> Gem::Version
|
|
130
|
-
attr_accessor full_gem_path: String
|
|
131
131
|
attr_accessor loaded_from: String?
|
|
132
132
|
attr_accessor post_install_message: String?
|
|
133
133
|
end
|
|
134
134
|
|
|
135
135
|
class Gem::BasicSpecification
|
|
136
136
|
def version: () -> Gem::Version
|
|
137
|
+
attr_accessor full_gem_path: String
|
|
137
138
|
def executables: () -> Array[String]
|
|
138
139
|
def name: () -> String
|
|
139
140
|
def full_name: () -> String
|
|
@@ -283,8 +283,11 @@ If you used the [AI-assisted setup](#the-fast-path-let-an-ai-agent-set-it-up),
|
|
|
283
283
|
the `rigor-project-init` skill already wrote one for you. To
|
|
284
284
|
write a starter by hand, `rigor init` emits `.rigor.dist.yml`
|
|
285
285
|
— the project default that gets committed, with `paths` and a
|
|
286
|
-
`severity_profile` filled in
|
|
287
|
-
|
|
286
|
+
`severity_profile` filled in. When your `Gemfile.lock` declares a
|
|
287
|
+
gem a bundled plugin models, the template suggests that plugin
|
|
288
|
+
under `plugins:`, commented out, for you to enable. `target_ruby`
|
|
289
|
+
is commented out until you set it to your project's Ruby, and the
|
|
290
|
+
rest is commented out too. That is all most projects need; the key
|
|
288
291
|
reference, the JSON-schema editor integration, and `includes:`
|
|
289
292
|
composition are in
|
|
290
293
|
[Configuration](../manual/03-configuration.md).
|
data/docs/handbook/11-sig-gen.md
CHANGED
|
@@ -155,6 +155,11 @@ The `sig.skipped.*` reasons are:
|
|
|
155
155
|
generic by an inline declaration and `sig/` does not declare
|
|
156
156
|
it yet, or names its type parameters otherwise. See
|
|
157
157
|
[Classes made generic inline](#classes-made-generic-inline).
|
|
158
|
+
- `sig.skipped.generic-reopening` — the method's class, or one
|
|
159
|
+
it is nested in, is declared generic by loaded RBS with a
|
|
160
|
+
type parameter that has a bound or a default, and `sig/`
|
|
161
|
+
does not declare it. See
|
|
162
|
+
[Reopening a generic class](#reopening-a-generic-class).
|
|
158
163
|
- `sig.skipped.inline-differs` — the method is declared
|
|
159
164
|
inline and in `sig/`, and the two disagree. A refusal:
|
|
160
165
|
`--write` and `--check` exit `1`. See
|
|
@@ -330,10 +335,34 @@ so a return inferred for the new line would describe
|
|
|
330
335
|
parameters that are about to change. Delete the `sig/` member
|
|
331
336
|
and re-run; sig-gen then writes the method afresh.
|
|
332
337
|
|
|
338
|
+
### Reopening a generic class
|
|
339
|
+
|
|
340
|
+
When your code reopens a class that loaded RBS declares
|
|
341
|
+
generic — `class Array`, `class Hash`, a gem's class, or one
|
|
342
|
+
your `sig/` declares — sig-gen writes the header with that
|
|
343
|
+
declaration's type parameters: `class Array[unchecked out E]`.
|
|
344
|
+
rbs rejects a reopening whose parameters differ, so a bare
|
|
345
|
+
`class Array` would fail the class, and every class whose
|
|
346
|
+
signature mentions it, with `GenericParameterMismatchError`.
|
|
347
|
+
The members still say `untyped` for the element type, and a
|
|
348
|
+
class whose name matches a copied parameter is written
|
|
349
|
+
anchored (`::E`), since a bare `E` would name the parameter.
|
|
350
|
+
|
|
351
|
+
The parameters are copied only when every one is plain: a
|
|
352
|
+
name, a variance and `unchecked`. A bound or a default
|
|
353
|
+
(`class Box[T < Comparable]`) is a type written for the
|
|
354
|
+
declaring file's namespace and could mean another class
|
|
355
|
+
where sig-gen writes, so that class's methods, and those of
|
|
356
|
+
classes nested in it, are skipped as
|
|
357
|
+
`sig.skipped.generic-reopening`. Declare the class in `sig/`
|
|
358
|
+
with its parameters and sig-gen writes the members into that
|
|
359
|
+
declaration. A file that already declares the class keeps its
|
|
360
|
+
own header.
|
|
361
|
+
|
|
333
362
|
### Classes made generic inline
|
|
334
363
|
|
|
335
|
-
sig-gen does not
|
|
336
|
-
declared generic inline (`# @rbs generic T`) is therefore not
|
|
364
|
+
sig-gen does not copy type parameters from an inline
|
|
365
|
+
declaration. A class declared generic inline (`# @rbs generic T`) is therefore not
|
|
337
366
|
opened in `sig/`: a header without its parameters would make
|
|
338
367
|
rbs reject the class, and every class whose signature mentions
|
|
339
368
|
it, with `GenericParameterMismatchError`. Its methods, and
|
|
@@ -626,6 +655,24 @@ list is the current state):
|
|
|
626
655
|
are recognised as user-authored and never produce a
|
|
627
656
|
duplicate `def` insertion.
|
|
628
657
|
|
|
658
|
+
Two rules shape the class declarations and type names around
|
|
659
|
+
those methods:
|
|
660
|
+
|
|
661
|
+
- **A subclass of a core or stdlib class** is declared even
|
|
662
|
+
when it has no method of its own to emit, so a method
|
|
663
|
+
returning one resolves: `class MyHash < Hash; end` is
|
|
664
|
+
written `class MyHash < ::Hash[untyped, untyped]`. The
|
|
665
|
+
declaration goes into the file written for its source file,
|
|
666
|
+
so it appears only when that source file has at least one
|
|
667
|
+
method to emit. A class some signature already declares is
|
|
668
|
+
left to that declaration.
|
|
669
|
+
- **A type name a namespace shadows** is written with a
|
|
670
|
+
leading `::`. Inside a `module Foo` that declares a
|
|
671
|
+
`Foo::Set`, a method returning a core `Set` is written
|
|
672
|
+
`-> ::Set[untyped]`, because RBS would read a bare `Set`
|
|
673
|
+
there as `Foo::Set`. Where nothing shadows the name, it is
|
|
674
|
+
written bare as before.
|
|
675
|
+
|
|
629
676
|
Method shapes the generator does **not** cover yet:
|
|
630
677
|
|
|
631
678
|
- `define_method(:name) { ... }`.
|
|
@@ -643,7 +690,7 @@ two are wired today, one is reserved.
|
|
|
643
690
|
| Policy | Behaviour |
|
|
644
691
|
| --- | --- |
|
|
645
692
|
| `untyped` (default) | Every parameter is spelled `untyped`. No inference-derived parameter contract is imposed on future callers. The user retains complete authorship over parameter typing. |
|
|
646
|
-
| `observed` | Collect argument types from every call site under `--observe=PATH...` (defaults to the configured `test_paths:`, or whichever of `spec/` and `test/` exist), union per parameter position, erase to RBS, emit the union. With no test root to observe, or a declared root that does not exist or is not read, sig-gen says so on stderr, and `--format=json` carries the same fact in a top-level `observation` key (below). |
|
|
693
|
+
| `observed` | Collect argument types from every call site under `--observe=PATH...` (defaults to the configured `test_paths:`, or whichever of `spec/` and `test/` exist), union per parameter position, erase to RBS, emit the union. A literal argument is widened to its class first, so `"hello"` proposes `String` (#2254). With no test root to observe, or a declared root that does not exist or is not read, sig-gen says so on stderr, and `--format=json` carries the same fact in a top-level `observation` key (below). |
|
|
647
694
|
| `observed-strict` | Reserved. Will additionally widen to capability roles (`_ToStr`, `_ToS`, …) once the role catalog ships. Currently rejected with a usage error. |
|
|
648
695
|
|
|
649
696
|
Under `--params=observed`, the `--print` / `--diff` JSON payload gains
|
|
@@ -20,7 +20,7 @@ unchanged. This appendix maps the vocabulary.
|
|
|
20
20
|
| Default behaviour | Inference, fall back silent | Inference, fall back silent |
|
|
21
21
|
| "Levels" | 0 – 10 (numeric) | `lenient` / `balanced` / `strict` (named) |
|
|
22
22
|
| Per-rule control | `ignoreErrors:` regex, level demotion | `disable:`, `severity_overrides:` |
|
|
23
|
-
| Baseline | `phpstan-baseline.neon` | `.rigor-baseline.yml` (managed) / `rigor.
|
|
23
|
+
| Baseline | `phpstan-baseline.neon` | `.rigor-baseline.yml` (managed) / `rigor-check.json` (ad-hoc) |
|
|
24
24
|
| Stub format | PHP stub files | RBS files |
|
|
25
25
|
| Custom narrowing | Type-Specifying Extensions | Plugins (Chapter 9) |
|
|
26
26
|
| Custom return shape | Dynamic Return Type Extensions | Plugin `dynamic_return` |
|
|
@@ -140,10 +140,10 @@ severity controls, and includes.
|
|
|
140
140
|
| `ignoreErrors:` (regex / pattern) | `disable:` (rule identifier or wildcard) |
|
|
141
141
|
| `parameters: ignoreErrors:` per-path | `# rigor:disable-file <rule>` at the file head |
|
|
142
142
|
| `includes:` | `includes:` |
|
|
143
|
-
| `phpstan-baseline.neon` | `.rigor-baseline.yml` (managed) — or `rigor.
|
|
144
|
-
| `phpstan analyse --generate-baseline` | `rigor baseline generate` (managed) — or `rigor check --format=json > rigor.
|
|
143
|
+
| `phpstan-baseline.neon` | `.rigor-baseline.yml` (managed) — or `rigor-check.json` (ad-hoc) |
|
|
144
|
+
| `phpstan analyse --generate-baseline` | `rigor baseline generate` (managed) — or `rigor check --format=json > rigor-check.json` (ad-hoc) |
|
|
145
145
|
| `phpstan analyse` | `rigor check` |
|
|
146
|
-
| `phpstan analyse --baseline` | `rigor check` with `baseline: .rigor-baseline.yml` configured (managed) — or `rigor diff rigor.
|
|
146
|
+
| `phpstan analyse --baseline` | `rigor check` with `baseline: .rigor-baseline.yml` configured (managed) — or `rigor diff rigor-check.json` (ad-hoc) |
|
|
147
147
|
| Path resolution: relative to declaring file | Path resolution: relative to declaring file (same rule). |
|
|
148
148
|
|
|
149
149
|
Rigor has two baseline mechanisms: a **managed** baseline
|
|
@@ -10,6 +10,8 @@ rigor <command> [options] [arguments]
|
|
|
10
10
|
`rigor help` prints the command list; `rigor version` prints
|
|
11
11
|
the installed version. An unknown command, or a malformed
|
|
12
12
|
option, exits `64` — the conventional "usage error" code.
|
|
13
|
+
See [`rigor help`](#rigor-help) for a single command's help and
|
|
14
|
+
the machine-readable list of commands and flags.
|
|
13
15
|
|
|
14
16
|
Every command that loads your project configuration also
|
|
15
17
|
accepts `--config=PATH` to point at a specific config file
|
|
@@ -46,7 +48,7 @@ check their arity, since another file may redefine them.
|
|
|
46
48
|
| `--no-cache` | Skip the persistent cache for this run. With `--incremental` it is a cold full analysis: the incremental snapshot and the run-result cache are neither read nor written, so the next plain `--incremental` run still uses the snapshot it had before. |
|
|
47
49
|
| `--incremental` | Re-analyse only the files changed since the last run plus the files that depend on them, serving the rest from a cross-process disk snapshot (ADR-46). Diagnostics are identical to a full run; a config / gem / version change (or a file added or removed) transparently forces a full re-analysis. A run with nothing changed is answered from the cache without starting the analyzer. See [Caching](12-caching.md). |
|
|
48
50
|
| `--verify-incremental` | Acceptance gate: run the incremental analyzer against a full `--no-cache` run and assert the diagnostics agree as a set and in the same order, then exit (0 on match, 1 on mismatch: the differing diagnostics for a set mismatch, or the first index where the order diverges for a same-set, different-order mismatch). It re-analyses half of an unchanged tree and serves the other half from cache, so it checks the cache-merge path but not that an edit re-checks every file it affects; `--verify-incremental-edits` adds that. |
|
|
49
|
-
| `--verify-incremental-edits=N` | With `--verify-incremental` (and implying it): after the check above, replay
|
|
51
|
+
| `--verify-incremental-edits=N` | With `--verify-incremental` (and implying it): after the check above, replay edits on each of `N` files spread over the analysed list, through an editor buffer, never on disk: the file emptied; the file reduced to its `class` / `module` declarations with every body dropped (skipped when that is the file itself, or holds no declaration); and up to two copies of the file each missing one statement of a `class` / `module` body, with everything else kept, so a finer dependency edge is the only thing that re-checks a reader (visibility calls such as `private` and `module_function` are dropped first, then other statements spread over the file). After each edit, the warm recheck of the baseline must equal a full analysis of the edited tree, or the run fails naming the edit and the file. Each replay costs a recheck and a full analysis. A replay the recheck declines (it would have been a full analysis) is counted in the OK line, and the run fails if every replay declined. Only removals are replayed, never an addition. Default 0. |
|
|
50
52
|
| `--clear-cache` | Delete the cache directory before running. |
|
|
51
53
|
| `--cache-stats` | Print the on-disk cache inventory when finished — on stdout under `--format text`, on stderr under every other format, so machine-readable output stays a parseable document. `--clear-cache`'s and `--verify-incremental`'s notes follow the same rule. |
|
|
52
54
|
| `--[no-]stats` | Print a run summary (files, classes, memory, wall time) to stderr. Default on. |
|
|
@@ -60,7 +62,7 @@ check their arity, since another file may redefine them.
|
|
|
60
62
|
| `--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). |
|
|
61
63
|
| `--no-bleeding-edge` | Ignore any configured `bleeding_edge:` selection for this run (adopt none). |
|
|
62
64
|
| `--no-tolerated-effects` | Check effect envelopes as if [`effects.tolerated:`](03-configuration.md) were empty — the audit switch for your discharge policy (ADR-103). Judgment only: the run, what it collects and its cache entry are identical either way, so this never costs a re-analysis. |
|
|
63
|
-
| `--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). |
|
|
65
|
+
| `--tmp-file=PATH --instead-of=PATH` | Editor mode: analyse `PATH` using the buffer in `--tmp-file`. Both required together, once per run (a repeat is a usage error). Alone, only the buffer's own file produces diagnostics; add `--incremental` for whole-project scope (see below). |
|
|
64
66
|
|
|
65
67
|
Exit `0` when no error-severity diagnostics remain, `1` when
|
|
66
68
|
any are reported, `64` on a usage error. `--fail-on` raises that
|
|
@@ -70,14 +72,16 @@ that want the stricter reading.
|
|
|
70
72
|
### Editor mode scope
|
|
71
73
|
|
|
72
74
|
`--tmp-file` / `--instead-of` on their own analyse **only** the
|
|
73
|
-
buffer's file.
|
|
74
|
-
|
|
75
|
+
buffer's file. The `--instead-of` logical path is analysed even when it
|
|
76
|
+
lies outside `paths:`, as it always has been. It still reads the rest of the
|
|
77
|
+
project's declarations (the classes and methods other files define), as `rigor check FILE`
|
|
75
78
|
does, but it reports nothing about what the unsaved edit does to the
|
|
76
79
|
rest of the project.
|
|
77
80
|
|
|
78
81
|
Adding `--incremental` analyses the **whole project with the buffer
|
|
79
82
|
substituted** — the edited file and the files that depend on it are
|
|
80
83
|
re-analysed, everything else is served from the incremental snapshot.
|
|
84
|
+
A buffer for a claimed template is analysed as its template unit, once.
|
|
81
85
|
An unsaved change to a method's return type therefore surfaces in its
|
|
82
86
|
callers, not just in the file being edited.
|
|
83
87
|
|
|
@@ -91,6 +95,11 @@ Two things to know:
|
|
|
91
95
|
exist only in your editor, and recording them would make the next
|
|
92
96
|
ordinary run believe it had already analysed a file in a state it
|
|
93
97
|
was never in.
|
|
98
|
+
- The buffer's file need not exist on disk yet: a new file is analysed
|
|
99
|
+
as an added file, with or without path arguments.
|
|
100
|
+
- Editor mode binds one buffer per run. Repeating `--tmp-file` or
|
|
101
|
+
`--instead-of` is a usage error (exit `64`), not a silent replacement
|
|
102
|
+
of the earlier pair.
|
|
94
103
|
|
|
95
104
|
`--verify-incremental` refuses a buffer: it compares against a full
|
|
96
105
|
analysis of the files on disk, which a buffer contradicts by
|
|
@@ -101,12 +110,41 @@ construction.
|
|
|
101
110
|
Write a starter configuration file.
|
|
102
111
|
|
|
103
112
|
```sh
|
|
104
|
-
rigor init [--path=PATH] [--force]
|
|
113
|
+
rigor init [--path=PATH] [--force] [--no-plugins]
|
|
105
114
|
```
|
|
106
115
|
|
|
107
116
|
Writes `.rigor.dist.yml` by default. `--path` chooses a
|
|
108
117
|
different target; `--force` overwrites an existing file.
|
|
109
|
-
Exit `1` if the file exists and `--force` was not given.
|
|
118
|
+
Exit `1` if the file exists and `--force` was not given. A `--path` whose
|
|
119
|
+
directory does not exist, or that cannot be written, is a usage error: one
|
|
120
|
+
`rigor init: cannot write PATH: REASON` line on stderr and exit `64`. The
|
|
121
|
+
directory is not created.
|
|
122
|
+
|
|
123
|
+
When the project has a `Gemfile.lock` in the working directory,
|
|
124
|
+
`rigor init` suggests the bundled plugins whose gems the lockfile
|
|
125
|
+
declares (the same read as [`rigor doctor`](#rigor-doctor)'s
|
|
126
|
+
plugin-gap check). The suggestions are commented out under
|
|
127
|
+
`plugins: []`, so nothing loads until you enable one: delete the
|
|
128
|
+
`[]` on the `plugins:` line, uncomment the entries you want, then
|
|
129
|
+
run `rigor plugins --strict`. A Rails project's `rails` also brings
|
|
130
|
+
in the Rails family, so the list can be long. Without a lockfile,
|
|
131
|
+
or when no locked gem has a bundled plugin, the template has no
|
|
132
|
+
suggestions.
|
|
133
|
+
|
|
134
|
+
Suggesting rather than enabling follows ADR-96 Criterion 2: a
|
|
135
|
+
lockfile's presence does not by itself opt a project into a
|
|
136
|
+
plugin's code.
|
|
137
|
+
|
|
138
|
+
In a Rails application (a `config/application.rb` in the working
|
|
139
|
+
directory), `rigor init` also suggests the source directories that
|
|
140
|
+
exist, `app` and `lib`. The active `paths:` stays `lib`; the
|
|
141
|
+
suggestion is a commented `paths:` line under it, which names what
|
|
142
|
+
was detected. A bare `rigor check` analyses only `lib` until you
|
|
143
|
+
delete the `paths:` list above and uncomment the line below. Other
|
|
144
|
+
layouts get no directory suggestion.
|
|
145
|
+
|
|
146
|
+
`--no-plugins` writes the template with no plugin suggestions, even
|
|
147
|
+
when a lockfile is present.
|
|
110
148
|
|
|
111
149
|
## `rigor annotate`
|
|
112
150
|
|
|
@@ -123,10 +161,16 @@ honours `NO_COLOR`; `--color` / `--no-color` override. When
|
|
|
123
161
|
colour is on and [`bat`](https://github.com/sharkdp/bat) is on
|
|
124
162
|
`PATH`, highlighting goes through bat (`--no-bat` opts out;
|
|
125
163
|
`--bat` warns if bat is missing and falls back to the built-in
|
|
126
|
-
colorizer). `--format=json` emits
|
|
127
|
-
instead of the annotated source. Exit `1` on a parse error or a
|
|
164
|
+
colorizer). `--format=json` emits an `{ "schema_version": 1, "annotations": { line => type } }`
|
|
165
|
+
document instead of the annotated source. Exit `1` on a parse error or a
|
|
128
166
|
missing file.
|
|
129
167
|
|
|
168
|
+
## JSON documents
|
|
169
|
+
|
|
170
|
+
Every `--format=json` document Rigor defines whose top level is an object, except the three named below, starts with an integer `schema_version` (currently `1`). Where a flag selects which document is printed, `mode` follows it: `rigor coverage` prints `precision`, `protection`, `mutation` or `protection-fused`, and `rigor plugins` prints `status` or `capabilities`. The key set is contract from v1.0.0: a minor release may add a key, and removing or renaming one needs a major.
|
|
171
|
+
|
|
172
|
+
`rigor lens` (its own `schema` / `revision`), `rigor baseline dump` (`version`) and `rigor check`'s CI formats (`sarif`, `gitlab`, ...) keep their own markers. `rigor type-of`, `rigor explain` and `rigor trace` are the exceptions and still print their current top-level shape (an array; for `type-of` a flat object or `{ results }`; for `explain <skip-reason>` a flat object); the next minor release switches them to `{ "schema_version": 1, "results" | "rules" | "skip_reasons" | "events": [...] }`. Until then each prints a note on stderr, and the matching MCP tools append the same note as an extra text block.
|
|
173
|
+
|
|
130
174
|
## `rigor type-of`
|
|
131
175
|
|
|
132
176
|
Print inferred types at one or more source positions.
|
|
@@ -148,7 +192,8 @@ wraps several results in a `results` array. Line queries add a
|
|
|
148
192
|
`line_enumerations` array whose `shown` and `total` counts make
|
|
149
193
|
truncation explicit. `--trace` records fail-soft fallbacks,
|
|
150
194
|
after the rows of a line table in text output. The editor-mode
|
|
151
|
-
`--tmp-file` / `--instead-of` pair is accepted as on `check
|
|
195
|
+
`--tmp-file` / `--instead-of` pair is accepted as on `check`, and a repeated flag is a usage error
|
|
196
|
+
(exit `64`) there too.
|
|
152
197
|
|
|
153
198
|
A class or constant that another project file declares reads as
|
|
154
199
|
`rigor check` types it (`singleton(User)`) when a bare
|
|
@@ -159,9 +204,13 @@ and never writes it. With no reusable snapshot (none yet, or one a
|
|
|
159
204
|
change made unusable, for example a changed configuration, lockfile, `sig/`, `pre_eval:`
|
|
160
205
|
file or required feature, an engine upgrade, or a snapshot written
|
|
161
206
|
for other roots) the probe types the one file on its own, so such a name reads
|
|
162
|
-
`Dynamic[top]`, and it prints nothing about it.
|
|
163
|
-
|
|
164
|
-
parameter
|
|
207
|
+
`Dynamic[top]`, and it prints nothing about it. With
|
|
208
|
+
`parameter_inference: true`, the types `check` infers for an
|
|
209
|
+
unannotated parameter come from the same snapshot (its recorded
|
|
210
|
+
call-site table), so `@v = v` reads as `check` types it, but only
|
|
211
|
+
while no project file has changed since the snapshot (an editor
|
|
212
|
+
buffer whose bytes differ from the snapshot counts as a change); once any file differs, or with the setting off
|
|
213
|
+
or no snapshot, those types are not shared.
|
|
165
214
|
|
|
166
215
|
A template a plugin compiles into Ruby (an ERB view under
|
|
167
216
|
`rigor-actionpack`) is probed the way `rigor check` analyses
|
|
@@ -521,11 +570,11 @@ a severity or a suppression line.
|
|
|
521
570
|
|
|
522
571
|
## `rigor diff`
|
|
523
572
|
|
|
524
|
-
Compare the current diagnostics against a saved
|
|
525
|
-
and report only what is new.
|
|
573
|
+
Compare the current diagnostics against a saved
|
|
574
|
+
`rigor check --format=json` result and report only what is new.
|
|
526
575
|
|
|
527
576
|
```sh
|
|
528
|
-
rigor diff [options] <
|
|
577
|
+
rigor diff [options] <rigor-check.json> [paths...]
|
|
529
578
|
```
|
|
530
579
|
|
|
531
580
|
`--current=PATH` compares against a saved diagnostics JSON
|
|
@@ -571,6 +620,18 @@ refuse a file, so a tighter return `--write` declines without
|
|
|
571
620
|
`--overwrite` does not fail it; `--check --overwrite` counts one.
|
|
572
621
|
See [handbook chapter 11](../handbook/11-sig-gen.md#keeping-sig-current-in-ci).
|
|
573
622
|
|
|
623
|
+
`--write` also repairs a header in any file under the signature directory it writes to (the directory
|
|
624
|
+
under the project root named like the last path component of the first `signature_paths:` entry, `sig/` by
|
|
625
|
+
default, vendored or generated `.rbs` under it included) that opens a generic class such as
|
|
626
|
+
`class Array` or `class Hash` without its type parameters (an earlier release wrote them), reporting
|
|
627
|
+
`repaired N generic header(s)`, and `--check` fails until it is written. In `--format=json` the row of a file
|
|
628
|
+
no method of the run maps to has `"source": null`. A class is repaired in all of its bare headers or in none:
|
|
629
|
+
when the body of any of them names a type spelt like one of the parameters (`def old: () -> E`), which the
|
|
630
|
+
parameter would capture, or one of them is in another `signature_paths:` entry, which `--write` never
|
|
631
|
+
rewrites, none is repaired. A `generic header left bare` line (`left_bare` in `--format=json`) names the files
|
|
632
|
+
and the reason, and `--check` does not fail on it. Write the name as `::E`, or fix the other file, to let the
|
|
633
|
+
repair through.
|
|
634
|
+
|
|
574
635
|
`--write` names each proposal it skipped (a member `sig/` already declares, an `alias` included, or one that
|
|
575
636
|
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
|
|
576
637
|
unchanged. See [handbook chapter 11](../handbook/11-sig-gen.md#safety-what---write-will-and-will-not-do).
|
|
@@ -614,7 +675,13 @@ would take every other type in the file down with it. Under
|
|
|
614
675
|
**refused** (the existing file is left untouched) and the command
|
|
615
676
|
exits `1`: you asked for a write and did not get one. Such a skip
|
|
616
677
|
is a bug in Rigor's RBS rendering, not in your code — please
|
|
617
|
-
report it.
|
|
678
|
+
report it. An existing target that does not parse as RBS in the
|
|
679
|
+
first place, and that sig-gen would write into, is refused the same
|
|
680
|
+
way, named on stdout as `REFUSED` with the parse location (the JSON
|
|
681
|
+
action is `skipped_unparseable`); `--check` fails on it too, so such a
|
|
682
|
+
target is never reported as up to date. An unparseable `sig/` file that
|
|
683
|
+
no emittable candidate maps to is not refused and still passes
|
|
684
|
+
`--check`. Fix its syntax error and re-run.
|
|
618
685
|
|
|
619
686
|
A method the generator declined for any other reason (a body
|
|
620
687
|
that proves only `untyped`, a user-authored declaration it will
|
|
@@ -634,10 +701,20 @@ Run the Language Server over stdio. See
|
|
|
634
701
|
rigor lsp [--transport=stdio] [--log=PATH] [--config=PATH]
|
|
635
702
|
```
|
|
636
703
|
|
|
637
|
-
`stdio` is the only transport in v1. `--log=PATH`
|
|
638
|
-
|
|
639
|
-
the server
|
|
640
|
-
|
|
704
|
+
`stdio` is the only transport in v1. `--log=PATH` appends the LSP
|
|
705
|
+
wire log to PATH: each JSON-RPC message the client sends (`<-`) and
|
|
706
|
+
each one the server writes (`->`), one line per message with a
|
|
707
|
+
timestamp, plus the server's debug output from the start of the
|
|
708
|
+
server loop to its end. The file is opened for appending before the
|
|
709
|
+
server starts, so an unwritable PATH exits with a usage error. An
|
|
710
|
+
exception that escapes the loop is written to the file with its
|
|
711
|
+
backtrace. Output written before the loop starts (configuration
|
|
712
|
+
loading and server setup) and any crash outside the loop still go to
|
|
713
|
+
stderr, as does the server's output when the file becomes unwritable
|
|
714
|
+
mid-session. A message the JSON encoder rejects (raw invalid UTF-8) is
|
|
715
|
+
logged in a scrubbed form. Without `--log`, no wire log is written and
|
|
716
|
+
the server's debug output goes to stderr; stdout carries only the
|
|
717
|
+
protocol.
|
|
641
718
|
|
|
642
719
|
## `rigor baseline`
|
|
643
720
|
|
|
@@ -661,6 +738,12 @@ rigor baseline <generate|regenerate|dump|drift|prune> [options]
|
|
|
661
738
|
`--baseline=PATH` to read a non-default baseline file. `dump`
|
|
662
739
|
also accepts `--format=text|json` for machine-readable output.
|
|
663
740
|
|
|
741
|
+
No subcommand takes a positional path: `generate` and `regenerate`
|
|
742
|
+
analyse the configured `paths:`, `drift` and `prune` audit them, and
|
|
743
|
+
`dump` reads the baseline file and filters with `--rule`/`--file`. A path argument is a usage error
|
|
744
|
+
(exit `64`). Narrow the scope with `paths:` in the configuration, not on
|
|
745
|
+
the command line.
|
|
746
|
+
|
|
664
747
|
## `rigor triage`
|
|
665
748
|
|
|
666
749
|
Summarise a diagnostic stream — rule distribution, **class/method
|
|
@@ -1011,15 +1094,22 @@ toolchain, so you can read a real, working plugin as a worked
|
|
|
1011
1094
|
example when authoring your own.
|
|
1012
1095
|
|
|
1013
1096
|
```sh
|
|
1014
|
-
rigor plugin <
|
|
1097
|
+
rigor plugin [<name>] [--path <name>] [--list] [--root]
|
|
1015
1098
|
```
|
|
1016
1099
|
|
|
1017
|
-
|
|
1100
|
+
The positional slot is a plugin *name*; alternative outputs are
|
|
1101
|
+
flags, the same grammar as `rigor skill` and `rigor docs`.
|
|
1102
|
+
|
|
1103
|
+
| Form | Purpose |
|
|
1018
1104
|
| --- | --- |
|
|
1019
|
-
| `list` | Table of every bundled plugin and example, name + absolute directory path (default
|
|
1020
|
-
|
|
|
1021
|
-
|
|
|
1022
|
-
|
|
|
1105
|
+
| `rigor plugin`, `--list` | Table of every bundled plugin and example, name + absolute directory path (the default). |
|
|
1106
|
+
| `<name>` | A header (dir / lib / sig / README paths) followed by the plugin's main source body inlined. |
|
|
1107
|
+
| `--path <name>` | One-line absolute path to the plugin's directory. |
|
|
1108
|
+
| `--root` | The `rigortype` gem root and its key subdirectories. |
|
|
1109
|
+
|
|
1110
|
+
The earlier verbs `list`, `path <name>`, `print <name>` and `root`
|
|
1111
|
+
still work for one minor release and print a deprecation notice on
|
|
1112
|
+
stderr naming the replacement; the output on stdout is the same.
|
|
1023
1113
|
|
|
1024
1114
|
Paths resolve at runtime from the gem location (a documented
|
|
1025
1115
|
caveat for container / cross-filesystem setups).
|
|
@@ -1275,6 +1365,42 @@ rigor upgrade
|
|
|
1275
1365
|
Until then it prints the current version and notes that upgrade is
|
|
1276
1366
|
queued. Exits `0`.
|
|
1277
1367
|
|
|
1368
|
+
## `rigor help`
|
|
1369
|
+
|
|
1370
|
+
```sh
|
|
1371
|
+
rigor help # the command list
|
|
1372
|
+
rigor help <command> # the same as `rigor <command> --help`
|
|
1373
|
+
rigor help --format=json # every command, its flags and formats
|
|
1374
|
+
```
|
|
1375
|
+
|
|
1376
|
+
`rigor help --format=json` prints the whole CLI surface as one JSON
|
|
1377
|
+
document, for tools and agents that would otherwise parse the help
|
|
1378
|
+
text:
|
|
1379
|
+
|
|
1380
|
+
```json
|
|
1381
|
+
{ "schema_version": 1, "version": "…", "commands": [ … ] }
|
|
1382
|
+
```
|
|
1383
|
+
|
|
1384
|
+
Each entry of `commands` has:
|
|
1385
|
+
|
|
1386
|
+
| Key | Value |
|
|
1387
|
+
| --- | --- |
|
|
1388
|
+
| `name` | The command name. |
|
|
1389
|
+
| `summary` | The one-line description `rigor help` prints. |
|
|
1390
|
+
| `usage` | The usage line (`Usage: rigor …`). |
|
|
1391
|
+
| `flags` | The command's own switches, each `{ "name", "arg", "optional", "desc" }`. `arg` is the argument's name, `null` for a switch that takes none, and `optional` is `true` when the argument may be left out (`--bleeding-edge[=LIST]`). `--[no-]x` is listed as the two flags `--x` and `--no-x`. |
|
|
1392
|
+
| `formats` | The values the command's own `--format` accepts, empty when it has none. A command that only has subcommands with the flag (`baseline`) lists none here. |
|
|
1393
|
+
| `subcommands` | One `{ "name", "usage", "flags", "formats" }` object per subcommand (`baseline dump`, `effects check`, `skill describe`), with the same meaning as above and empty arrays where the subcommand has nothing to list. |
|
|
1394
|
+
| `mcp_tool` | The [MCP](10-mcp-server.md) tool that mirrors the command, or `null`. |
|
|
1395
|
+
|
|
1396
|
+
The list covers every command above plus `help` and `version`. The
|
|
1397
|
+
text help is rendered from the same list.
|
|
1398
|
+
|
|
1399
|
+
`rigor help <command>` takes one command: a second word
|
|
1400
|
+
(`rigor help baseline drift`) is refused with exit `64`, and an
|
|
1401
|
+
unknown command exits `64` too. Flags after the command name are
|
|
1402
|
+
ignored rather than parsed.
|
|
1403
|
+
|
|
1278
1404
|
## Environment variables
|
|
1279
1405
|
|
|
1280
1406
|
Most behaviour is driven by flags and `.rigor.yml`; a few
|
|
@@ -24,7 +24,7 @@ Relative paths in a config file resolve against that file's own directory, with
|
|
|
24
24
|
`rigor` runs from. They match only when you run `rigor` from the directory that holds the config file, which is
|
|
25
25
|
the usual case; with `--config path/to/.rigor.yml` from elsewhere, give these three as absolute paths.
|
|
26
26
|
A leading `~/` (or a bare `~`) in a path setting expands to your home directory; `~name` is an ordinary
|
|
27
|
-
directory called `~name`, not another user's home. This covers `paths:`, `signature_paths:`, `test_paths:`,
|
|
27
|
+
directory called `~name`, not another user's home. This covers `paths:`, `signature_paths:`, `core_root:`, `test_paths:`,
|
|
28
28
|
`pre_eval:`, `plugins_io.allowed_paths:`, `includes:`, `bundler.bundle_path:`, `bundler.lockfile:` and
|
|
29
29
|
`rbs_collection.lockfile:`. It does not apply to `cache.path:`, `baseline:` or `effects.snapshot.path:`, which stay
|
|
30
30
|
literal and relative to the working directory.
|
|
@@ -78,9 +78,39 @@ cache:
|
|
|
78
78
|
| --- | --- | --- | --- |
|
|
79
79
|
| `libraries` | Array | `[]` | Standard-library / gem names whose bundled RBS to load. |
|
|
80
80
|
| `signature_paths` | Array | `nil` | Extra directories of `.rbs` files. Relative entries resolve against the config file's directory. |
|
|
81
|
+
| `core_root` | String | `nil` | A directory of core `.rbs` files loaded **instead of** the `rbs` gem's own core, such as one [rbs-shifter](https://github.com/rigortype/rbs-shifter) generates for an older CRuby. A relative path resolves against the config file's directory. `nil` loads the gem's core. See [Analysing for an older Ruby](#analysing-for-an-older-ruby). |
|
|
81
82
|
| `pre_eval` | Array | `[]` | Files (or globs) walked before per-file analysis, to register project monkey-patches and publish their top-level constants project-wide. The walker does not follow `require` / `require_relative`, so list the files in load order: a method declared in two files takes the last-listed one, and a file that requires a later-listed one is still read in list order. `type-of`, `type-scan`, `trace`, `annotate` and `sig-gen` read the patches too, so they type a patched method as `rigor check` does. |
|
|
82
83
|
| `plugins` | Array | `[]` | Plugins to activate — see [Using plugins](07-plugins.md). |
|
|
83
84
|
|
|
85
|
+
#### Analysing for an older Ruby
|
|
86
|
+
|
|
87
|
+
Rigor runs on Ruby 4.0, and its bundled core signatures describe Ruby 4.0. A project that runs on an older
|
|
88
|
+
Ruby can call a method that version does not have, and Rigor accepts the call. To check against the older
|
|
89
|
+
API, point `core_root:` at a core signature directory written for it:
|
|
90
|
+
|
|
91
|
+
```yaml
|
|
92
|
+
target_ruby: "3.3"
|
|
93
|
+
core_root: vendor/rbs-shifter/3.3/core
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
`core_root:` replaces the core, while `signature_paths:` only adds to it. A method that a signature directory
|
|
97
|
+
omits stays declared by the default core, so `signature_paths:` cannot remove one. With the core above,
|
|
98
|
+
`[1, 2].rfind { ... }` reports `call.undefined-method` and `" text ".strip(" ")` reports `call.wrong-arity`.
|
|
99
|
+
Project signatures, plugins and `libraries:` still load on top of it. `target_ruby:` sets the syntax Rigor
|
|
100
|
+
parses; it does not choose a core.
|
|
101
|
+
|
|
102
|
+
A `core_root:` that does not exist, is not a directory, holds no `.rbs` file, lies inside (or contains) one of
|
|
103
|
+
your `signature_paths:`, or does not build an RBS environment stops the run with exit code 64. A core class
|
|
104
|
+
whose definition fails to build because of the core's own files is reported as an
|
|
105
|
+
`rbs.coverage.definition-build-failed` error:
|
|
106
|
+
|
|
107
|
+
```
|
|
108
|
+
rigor: core_root: "/path/to/vendor/rbs-shifter/3.3/core" does not exist
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
The cache keys on the directory and on the contents of its files, so switching cores or regenerating one
|
|
112
|
+
invalidates cached results, including in a running language server.
|
|
113
|
+
|
|
84
114
|
### Signature generation
|
|
85
115
|
|
|
86
116
|
| Key | Type | Default | Meaning |
|
|
@@ -144,7 +174,10 @@ is left alone, other than the reserved run-level rows (`rbs.coverage.…`,
|
|
|
144
174
|
those rows are the intended keys and are never flagged, while a bare plugin
|
|
145
175
|
rule, `all`, or a `plugin.`-qualified key for an unconfigured plugin is. The same findings appear in the
|
|
146
176
|
`--format=json` payload under `config_warnings` (each tagged with a
|
|
147
|
-
`kind`), so CI can assert on them.
|
|
177
|
+
`kind`), so CI can assert on them. The [language server](09-editor-integration.md)
|
|
178
|
+
shows each one as a `window/showMessage` warning, and every
|
|
179
|
+
[MCP tool](10-mcp-server.md#tool-reference) that takes a `config`
|
|
180
|
+
argument includes them in its result.
|
|
148
181
|
|
|
149
182
|
### Diagnostics
|
|
150
183
|
|
|
@@ -194,7 +227,7 @@ project Ruby's gem home without running your toolchain. If `rigor check`'s
|
|
|
194
227
|
`--stats` shows gems whose RBS it could not find, point it at the bundle
|
|
195
228
|
explicitly with `bundler.bundle_path:`, or supply signatures another way:
|
|
196
229
|
`rbs collection install` (auto-discovered) or `dependencies.source_inference:`.
|
|
197
|
-
| `rbs_collection.auto_detect` | Boolean | `true` | Auto-discover `rbs_collection.lock.yaml`. |
|
|
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). |
|
|
198
231
|
| `rbs_collection.lockfile` | String | `nil` | Explicit `rbs_collection.lock.yaml` path. |
|
|
199
232
|
| `dependencies.source_inference` | Array | `[]` | Per-gem source-inference modes (ADR-10). |
|
|
200
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. |
|