rigortype 0.4.5 → 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 +61 -5
- data/docs/handbook/appendix-phpstan.md +4 -4
- data/docs/manual/02-cli-reference.md +192 -27
- data/docs/manual/03-configuration.md +38 -4
- data/docs/manual/04-diagnostics.md +1 -1
- data/docs/manual/06-baseline.md +6 -4
- data/docs/manual/09-editor-integration.md +13 -2
- data/docs/manual/10-mcp-server.md +47 -3
- data/docs/manual/12-caching.md +9 -1
- data/docs/manual/plugins/rigor-actionmailer.md +30 -0
- data/docs/manual/plugins/rigor-actionpack.md +49 -11
- data/docs/manual/plugins/rigor-activesupport-core-ext.md +20 -1
- data/docs/manual/plugins/rigor-devise.md +15 -0
- data/docs/manual/plugins/rigor-rspec.md +2 -1
- data/lib/rigor/analysis/baseline.rb +24 -27
- data/lib/rigor/analysis/buffer_binding.rb +14 -0
- 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 +105 -12
- data/lib/rigor/analysis/check_rules/ivar_write_collector.rb +143 -15
- data/lib/rigor/analysis/check_rules/lexical_method_sites.rb +4 -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/rbs_receiver_surface.rb +66 -3
- data/lib/rigor/analysis/check_rules/rebinding_block_callees/dispatch.rb +112 -0
- data/lib/rigor/analysis/check_rules/rebinding_block_callees.rb +394 -0
- data/lib/rigor/analysis/check_rules/return_in_ensure_collector.rb +1 -2
- data/lib/rigor/analysis/check_rules/ruby_deprecations.rb +7 -0
- 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 +53 -2
- data/lib/rigor/analysis/check_rules/void_value_use_collector.rb +1 -1
- data/lib/rigor/analysis/check_rules.rb +217 -52
- data/lib/rigor/analysis/crash_signature.rb +2 -2
- data/lib/rigor/analysis/dependency_recorder.rb +15 -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 +154 -0
- data/lib/rigor/analysis/fact_store.rb +3 -3
- data/lib/rigor/analysis/incremental.rb +37 -0
- 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 +202 -43
- data/lib/rigor/analysis/path_expansion.rb +41 -0
- data/lib/rigor/analysis/require_relative_closure.rb +100 -0
- data/lib/rigor/analysis/rule_catalog.rb +7 -3
- data/lib/rigor/analysis/run_disclosure_credit.rb +80 -0
- data/lib/rigor/analysis/run_disclosure_ledger.rb +155 -0
- data/lib/rigor/analysis/run_stats.rb +2 -2
- data/lib/rigor/analysis/runner/buffer_pool_dispatcher.rb +8 -4
- data/lib/rigor/analysis/runner/declaration_position.rb +1 -1
- data/lib/rigor/analysis/runner/diagnostic_aggregator.rb +204 -96
- data/lib/rigor/analysis/runner/effect_envelope_pass.rb +1 -1
- data/lib/rigor/analysis/runner/pool_coordinator.rb +157 -320
- data/lib/rigor/analysis/runner/project_pre_passes.rb +48 -6
- 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/scan_environment.rb +51 -0
- data/lib/rigor/analysis/runner/worker_payload.rb +36 -0
- data/lib/rigor/analysis/runner.rb +233 -120
- 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 +38 -33
- 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 +60 -18
- 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 +188 -93
- 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 +27 -21
- 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 +17 -13
- data/lib/rigor/cli/lsp_command.rb +250 -23
- data/lib/rigor/cli/mcp_command.rb +14 -8
- 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 +60 -4
- data/lib/rigor/cli/plugin_command.rb +93 -46
- data/lib/rigor/cli/plugins_command.rb +22 -18
- data/lib/rigor/cli/plugins_renderer.rb +34 -8
- 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 +23 -16
- data/lib/rigor/cli/sig_gen_command.rb +130 -34
- 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 +18 -12
- data/lib/rigor/cli/type_of_project_scope.rb +24 -0
- 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 +17 -6
- data/lib/rigor/configuration/severity_profile.rb +5 -5
- data/lib/rigor/configuration.rb +86 -34
- 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 +592 -70
- data/lib/rigor/environment/reflection.rb +7 -7
- data/lib/rigor/environment/required_features.rb +136 -32
- data/lib/rigor/environment/ruby_library_roots.rb +122 -0
- data/lib/rigor/environment/vendored_signature_plan.rb +153 -0
- data/lib/rigor/environment.rb +44 -11
- 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 +126 -0
- 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 +170 -0
- 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 +204 -12
- data/lib/rigor/inference/definer_resolution.rb +21 -5
- 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/error_info.rb +17 -3
- data/lib/rigor/inference/expression_typer.rb +173 -57
- data/lib/rigor/inference/external_ancestor_resolution.rb +3 -4
- data/lib/rigor/inference/global_write_census.rb +110 -1
- 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 +246 -0
- data/lib/rigor/inference/key_presence_guard.rb +2 -1
- data/lib/rigor/inference/loop_value_record.rb +57 -0
- data/lib/rigor/inference/match_rebinding/frame.rb +65 -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 +113 -12
- 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 +7 -3
- 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 +59 -24
- 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 +109 -29
- data/lib/rigor/inference/module_function_state/spellings.rb +64 -0
- data/lib/rigor/inference/module_function_state.rb +23 -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 +162 -29
- data/lib/rigor/inference/narrowing.rb +113 -38
- data/lib/rigor/inference/object_mixins.rb +13 -1
- 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_seed_tables.rb +2 -1
- data/lib/rigor/inference/project_yielder.rb +122 -0
- 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 +9 -1
- data/lib/rigor/inference/scope_indexer/constant_ivar_value.rb +93 -0
- data/lib/rigor/inference/scope_indexer/declared_ivar_types.rb +64 -0
- data/lib/rigor/inference/scope_indexer/declared_param_writes.rb +205 -0
- 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/unseen_ivar_writers.rb +133 -0
- data/lib/rigor/inference/scope_indexer.rb +614 -146
- data/lib/rigor/inference/self_call_ivar_writes.rb +101 -17
- 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 +3036 -278
- data/lib/rigor/inference/struct_fold_safety.rb +4 -6
- data/lib/rigor/inference/synthetic_method_index.rb +23 -0
- data/lib/rigor/inference/synthetic_method_scanner/project_members.rb +130 -0
- data/lib/rigor/inference/synthetic_method_scanner.rb +73 -14
- 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 +9 -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 +28 -9
- 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 +98 -4
- 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 +12 -6
- 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 +82 -3
- data/lib/rigor/mcp.rb +1 -1
- data/lib/rigor/plugin/access_denied_error.rb +1 -2
- data/lib/rigor/plugin/base.rb +26 -11
- 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 +38 -16
- data/lib/rigor/plugin/registry.rb +41 -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 +96 -2
- 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 +25 -2
- 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 +379 -36
- 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 +668 -84
- 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 +7 -6
- 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/rbs_validity.rb +1 -1
- data/lib/rigor/sig_gen/renderer.rb +21 -12
- data/lib/rigor/sig_gen/skip_reason_catalog.rb +15 -2
- data/lib/rigor/sig_gen/type_elaborator.rb +21 -5
- 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 +13 -16
- data/lib/rigor/type/constant.rb +48 -7
- data/lib/rigor/type/hash_shape.rb +26 -40
- data/lib/rigor/type/struct_instance.rb +3 -2
- 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 +89 -70
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_index.rb +4 -2
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer.rb +25 -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 +79 -19
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/effects.rb +1 -1
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob.rb +6 -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-devise/lib/rigor/plugin/devise.rb +5 -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 +7 -6
- 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 +102 -11
- 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 +5 -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/plugins/rigor-typelizer/lib/rigor/plugin/typelizer.rb +1 -1
- data/sig/rigor/analysis/baseline.rbs +0 -2
- 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/file_collection.rbs +5 -6
- data/sig/rigor/effects/registry.rbs +8 -6
- data/sig/rigor/effects/summary.rbs +6 -5
- data/sig/rigor/environment.rbs +5 -3
- data/sig/rigor/inference/optimistic_origin.rbs +11 -0
- data/sig/rigor/inference.rbs +10 -1
- data/sig/rigor/plugin/additional_initializer.rbs +0 -5
- data/sig/rigor/plugin/base.rbs +1 -0
- data/sig/rigor/plugin/effect_ancestry.rbs +6 -4
- data/sig/rigor/plugin/effect_attribution.rbs +25 -10
- data/sig/rigor/plugin/effect_edge.rbs +12 -5
- data/sig/rigor/plugin/effect_entry_points.rbs +8 -3
- data/sig/rigor/plugin/io_boundary.rbs +6 -5
- data/sig/rigor/plugin/manifest.rbs +16 -18
- data/sig/rigor/plugin/protocol_contract.rbs +6 -9
- data/sig/rigor/plugin/registry.rbs +1 -1
- data/sig/rigor/scope.rbs +51 -50
- data/sig/rigor/type.rbs +0 -6
- 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 +55 -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
|
|
@@ -538,8 +567,17 @@ overrides the method with the other one is not reported as
|
|
|
538
567
|
widening the return. A body that returns only `nil` keeps
|
|
539
568
|
the `untyped`: it is the shape of a template method a
|
|
540
569
|
subclass fills in, and `-> nil` would make every override
|
|
541
|
-
that returns a value a widening.
|
|
542
|
-
|
|
570
|
+
that returns a value a widening. A literal inside a tuple, a
|
|
571
|
+
record or a type argument is widened the same way while the
|
|
572
|
+
shape stays (`-> [1, "a"]` becomes `-> [Integer, String]`,
|
|
573
|
+
`-> { a: 1 }` becomes `-> { a: Integer }`); of the generic
|
|
574
|
+
types, only the arguments of `Array`, `Hash`, `Set`, `Range`
|
|
575
|
+
and `Enumerator` are widened. `nil` inside a union or a shape
|
|
576
|
+
and a computed `Float` are proposed as they are. When the
|
|
577
|
+
method also carries an inline `# @rbs` annotation for its
|
|
578
|
+
parameters only, a return holding a literal that would be
|
|
579
|
+
widened, nested or not, is not proposed at all and the
|
|
580
|
+
`untyped` stays. An `untyped` that
|
|
543
581
|
only the inline reader synthesizes for a `def` you did not
|
|
544
582
|
annotate keeps the literal, as does a method no `.rbs`
|
|
545
583
|
declares — the literal is still the strictest thing the body
|
|
@@ -617,6 +655,24 @@ list is the current state):
|
|
|
617
655
|
are recognised as user-authored and never produce a
|
|
618
656
|
duplicate `def` insertion.
|
|
619
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
|
+
|
|
620
676
|
Method shapes the generator does **not** cover yet:
|
|
621
677
|
|
|
622
678
|
- `define_method(:name) { ... }`.
|
|
@@ -634,7 +690,7 @@ two are wired today, one is reserved.
|
|
|
634
690
|
| Policy | Behaviour |
|
|
635
691
|
| --- | --- |
|
|
636
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. |
|
|
637
|
-
| `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). |
|
|
638
694
|
| `observed-strict` | Reserved. Will additionally widen to capability roles (`_ToStr`, `_ToS`, …) once the role catalog ships. Currently rejected with a usage error. |
|
|
639
695
|
|
|
640
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
|
|
@@ -28,15 +30,25 @@ rigor check [paths...]
|
|
|
28
30
|
`paths` are files or directories; when omitted, Rigor checks
|
|
29
31
|
the `paths:` list from the configuration file.
|
|
30
32
|
|
|
33
|
+
Only the files you name are reported on, but Rigor reads the
|
|
34
|
+
declarations in the configured `paths:` too, so a file resolves a
|
|
35
|
+
class or constant that another file declares. A file outside
|
|
36
|
+
`paths:` also reads the files it loads with a literal
|
|
37
|
+
`require_relative "..."`, and the files those load in turn. Their
|
|
38
|
+
classes, modules and constants resolve and their methods count as
|
|
39
|
+
defined, but Rigor does not infer what those methods return or
|
|
40
|
+
check their arity, since another file may redefine them.
|
|
41
|
+
|
|
31
42
|
| Option | Effect |
|
|
32
43
|
| --- | --- |
|
|
33
|
-
| `--config=PATH` | Use a specific config file instead of auto-discovery. |
|
|
44
|
+
| `--config=PATH` | Use a specific config file instead of auto-discovery. A path that does not exist is an error (exit 64), not a run with the defaults. |
|
|
34
45
|
| `--format=FORMAT` | Output format. Default `text`. Also `json` (structured stream), plus the CI-native renderings `sarif`, `github`, `gitlab`, `checkstyle`, `junit`, and `teamcity` — see [Running Rigor in CI](11-ci.md). |
|
|
35
46
|
| `--no-ci-detect` | Disable CI auto-detection — by default `text` output also emits the running CI's native annotations / hint (`RIGOR_CI_DETECT=0` does the same). See [Running Rigor in CI § auto-detection](11-ci.md). |
|
|
36
47
|
| `--explain` | Surface fail-soft fallback events as `info` diagnostics. |
|
|
37
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. |
|
|
38
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). |
|
|
39
|
-
| `--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).
|
|
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. |
|
|
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. |
|
|
40
52
|
| `--clear-cache` | Delete the cache directory before running. |
|
|
41
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. |
|
|
42
54
|
| `--[no-]stats` | Print a run summary (files, classes, memory, wall time) to stderr. Default on. |
|
|
@@ -50,7 +62,7 @@ the `paths:` list from the configuration file.
|
|
|
50
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). |
|
|
51
63
|
| `--no-bleeding-edge` | Ignore any configured `bleeding_edge:` selection for this run (adopt none). |
|
|
52
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. |
|
|
53
|
-
| `--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). |
|
|
54
66
|
|
|
55
67
|
Exit `0` when no error-severity diagnostics remain, `1` when
|
|
56
68
|
any are reported, `64` on a usage error. `--fail-on` raises that
|
|
@@ -60,12 +72,16 @@ that want the stricter reading.
|
|
|
60
72
|
### Editor mode scope
|
|
61
73
|
|
|
62
74
|
`--tmp-file` / `--instead-of` on their own analyse **only** the
|
|
63
|
-
buffer's file
|
|
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`
|
|
78
|
+
does, but it reports nothing about what the unsaved edit does to the
|
|
64
79
|
rest of the project.
|
|
65
80
|
|
|
66
81
|
Adding `--incremental` analyses the **whole project with the buffer
|
|
67
82
|
substituted** — the edited file and the files that depend on it are
|
|
68
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.
|
|
69
85
|
An unsaved change to a method's return type therefore surfaces in its
|
|
70
86
|
callers, not just in the file being edited.
|
|
71
87
|
|
|
@@ -79,6 +95,11 @@ Two things to know:
|
|
|
79
95
|
exist only in your editor, and recording them would make the next
|
|
80
96
|
ordinary run believe it had already analysed a file in a state it
|
|
81
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.
|
|
82
103
|
|
|
83
104
|
`--verify-incremental` refuses a buffer: it compares against a full
|
|
84
105
|
analysis of the files on disk, which a buffer contradicts by
|
|
@@ -89,12 +110,41 @@ construction.
|
|
|
89
110
|
Write a starter configuration file.
|
|
90
111
|
|
|
91
112
|
```sh
|
|
92
|
-
rigor init [--path=PATH] [--force]
|
|
113
|
+
rigor init [--path=PATH] [--force] [--no-plugins]
|
|
93
114
|
```
|
|
94
115
|
|
|
95
116
|
Writes `.rigor.dist.yml` by default. `--path` chooses a
|
|
96
117
|
different target; `--force` overwrites an existing file.
|
|
97
|
-
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.
|
|
98
148
|
|
|
99
149
|
## `rigor annotate`
|
|
100
150
|
|
|
@@ -111,10 +161,16 @@ honours `NO_COLOR`; `--color` / `--no-color` override. When
|
|
|
111
161
|
colour is on and [`bat`](https://github.com/sharkdp/bat) is on
|
|
112
162
|
`PATH`, highlighting goes through bat (`--no-bat` opts out;
|
|
113
163
|
`--bat` warns if bat is missing and falls back to the built-in
|
|
114
|
-
colorizer). `--format=json` emits
|
|
115
|
-
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
|
|
116
166
|
missing file.
|
|
117
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
|
+
|
|
118
174
|
## `rigor type-of`
|
|
119
175
|
|
|
120
176
|
Print inferred types at one or more source positions.
|
|
@@ -136,7 +192,25 @@ wraps several results in a `results` array. Line queries add a
|
|
|
136
192
|
`line_enumerations` array whose `shown` and `total` counts make
|
|
137
193
|
truncation explicit. `--trace` records fail-soft fallbacks,
|
|
138
194
|
after the rows of a line table in text output. The editor-mode
|
|
139
|
-
`--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.
|
|
197
|
+
|
|
198
|
+
A class or constant that another project file declares reads as
|
|
199
|
+
`rigor check` types it (`singleton(User)`) when a bare
|
|
200
|
+
`rigor check --incremental` has left a snapshot for the project:
|
|
201
|
+
`type-of` folds the cross-file declarations from that snapshot's
|
|
202
|
+
per-file bundles, re-reading any file whose bytes changed since,
|
|
203
|
+
and never writes it. With no reusable snapshot (none yet, or one a
|
|
204
|
+
change made unusable, for example a changed configuration, lockfile, `sig/`, `pre_eval:`
|
|
205
|
+
file or required feature, an engine upgrade, or a snapshot written
|
|
206
|
+
for other roots) the probe types the one file on its own, so such a name reads
|
|
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.
|
|
140
214
|
|
|
141
215
|
A template a plugin compiles into Ruby (an ERB view under
|
|
142
216
|
`rigor-actionpack`) is probed the way `rigor check` analyses
|
|
@@ -162,7 +236,9 @@ and is probed as plain Ruby, parse error included.
|
|
|
162
236
|
|
|
163
237
|
The four probe commands — `type-of`, `type-scan`, `trace` and
|
|
164
238
|
`annotate` — build their environment fresh on every invocation
|
|
165
|
-
and never read or write the persistent cache
|
|
239
|
+
and never read or write the persistent cache (apart from the
|
|
240
|
+
read-only snapshot lookup `type-of` makes for the project's
|
|
241
|
+
declarations, above). That is why none
|
|
166
242
|
of them takes `--no-cache`: the flag would have nothing to skip.
|
|
167
243
|
A probe therefore types against the environment `rigor check
|
|
168
244
|
--no-cache` analyses with. The environment a cached (default)
|
|
@@ -494,11 +570,11 @@ a severity or a suppression line.
|
|
|
494
570
|
|
|
495
571
|
## `rigor diff`
|
|
496
572
|
|
|
497
|
-
Compare the current diagnostics against a saved
|
|
498
|
-
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.
|
|
499
575
|
|
|
500
576
|
```sh
|
|
501
|
-
rigor diff [options] <
|
|
577
|
+
rigor diff [options] <rigor-check.json> [paths...]
|
|
502
578
|
```
|
|
503
579
|
|
|
504
580
|
`--current=PATH` compares against a saved diagnostics JSON
|
|
@@ -532,12 +608,30 @@ rigor sig-gen [paths]
|
|
|
532
608
|
| `--no-cache` | Do not read or write the analysis cache. Only effect collection uses it. |
|
|
533
609
|
| `--format=text\|json` | Output format. |
|
|
534
610
|
|
|
611
|
+
A `paths` argument that does not exist, or is neither a directory nor a `.rb` file, is reported the way
|
|
612
|
+
`rigor check` reports it: on stderr as `path:1:1: error: …`, or under `diagnostics` in `--print` and `--diff`
|
|
613
|
+
JSON output. When no argument is readable this exits `1`, under every mode, `--write` and `--check` included.
|
|
614
|
+
The configured default `paths:` count too, so `paths: [lib]` with no `lib/` directory exits `1`. A `--config`
|
|
615
|
+
that names no file, is a directory, or is empty is a usage error and exits `64`.
|
|
616
|
+
|
|
535
617
|
`--print`, `--diff`, `--write` and `--check` are mutually exclusive.
|
|
536
618
|
`--check` fails exactly when `--write` would create, change or
|
|
537
619
|
refuse a file, so a tighter return `--write` declines without
|
|
538
620
|
`--overwrite` does not fail it; `--check --overwrite` counts one.
|
|
539
621
|
See [handbook chapter 11](../handbook/11-sig-gen.md#keeping-sig-current-in-ci).
|
|
540
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
|
+
|
|
541
635
|
`--write` names each proposal it skipped (a member `sig/` already declares, an `alias` included, or one that
|
|
542
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
|
|
543
637
|
unchanged. See [handbook chapter 11](../handbook/11-sig-gen.md#safety-what---write-will-and-will-not-do).
|
|
@@ -581,7 +675,13 @@ would take every other type in the file down with it. Under
|
|
|
581
675
|
**refused** (the existing file is left untouched) and the command
|
|
582
676
|
exits `1`: you asked for a write and did not get one. Such a skip
|
|
583
677
|
is a bug in Rigor's RBS rendering, not in your code — please
|
|
584
|
-
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.
|
|
585
685
|
|
|
586
686
|
A method the generator declined for any other reason (a body
|
|
587
687
|
that proves only `untyped`, a user-authored declaration it will
|
|
@@ -601,10 +701,20 @@ Run the Language Server over stdio. See
|
|
|
601
701
|
rigor lsp [--transport=stdio] [--log=PATH] [--config=PATH]
|
|
602
702
|
```
|
|
603
703
|
|
|
604
|
-
`stdio` is the only transport in v1. `--log=PATH`
|
|
605
|
-
|
|
606
|
-
the server
|
|
607
|
-
|
|
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.
|
|
608
718
|
|
|
609
719
|
## `rigor baseline`
|
|
610
720
|
|
|
@@ -628,6 +738,12 @@ rigor baseline <generate|regenerate|dump|drift|prune> [options]
|
|
|
628
738
|
`--baseline=PATH` to read a non-default baseline file. `dump`
|
|
629
739
|
also accepts `--format=text|json` for machine-readable output.
|
|
630
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
|
+
|
|
631
747
|
## `rigor triage`
|
|
632
748
|
|
|
633
749
|
Summarise a diagnostic stream — rule distribution, **class/method
|
|
@@ -640,7 +756,7 @@ rigor triage [paths]
|
|
|
640
756
|
|
|
641
757
|
`--top=N` sets the hotspot count (default 10); `--hints-only`,
|
|
642
758
|
`--selectors-only`, and `--no-hints` select which sections print.
|
|
643
|
-
`triage` is advisory and
|
|
759
|
+
`triage` is advisory and exits `0` once it runs — it never gates a build; a usage error exits `64`.
|
|
644
760
|
|
|
645
761
|
By default the distribution, selectors, and hotspots sections count
|
|
646
762
|
only the **actionable** diagnostics (`error` + `warning`). `info`
|
|
@@ -946,6 +1062,11 @@ loaded from (a `path:` line in text, a `"path"` key in JSON), so
|
|
|
946
1062
|
if a stale installed gem is shadowing a newer checkout's bundled
|
|
947
1063
|
plugin copy the mismatch is visible at a glance.
|
|
948
1064
|
|
|
1065
|
+
A plugin that declares `per_invocation_classes:` or
|
|
1066
|
+
`per_invocation_non_action_macros:` ([ADR-125](../adr/125-per-invocation-classes.md))
|
|
1067
|
+
also gets a line for each in text, and a key in JSON (an empty
|
|
1068
|
+
array when it declares none).
|
|
1069
|
+
|
|
949
1070
|
```sh
|
|
950
1071
|
rigor plugins [--format=text|json] [--strict] [--capabilities] [--config=PATH]
|
|
951
1072
|
```
|
|
@@ -973,15 +1094,22 @@ toolchain, so you can read a real, working plugin as a worked
|
|
|
973
1094
|
example when authoring your own.
|
|
974
1095
|
|
|
975
1096
|
```sh
|
|
976
|
-
rigor plugin <
|
|
1097
|
+
rigor plugin [<name>] [--path <name>] [--list] [--root]
|
|
977
1098
|
```
|
|
978
1099
|
|
|
979
|
-
|
|
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 |
|
|
980
1104
|
| --- | --- |
|
|
981
|
-
| `list` | Table of every bundled plugin and example, name + absolute directory path (default
|
|
982
|
-
|
|
|
983
|
-
|
|
|
984
|
-
|
|
|
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.
|
|
985
1113
|
|
|
986
1114
|
Paths resolve at runtime from the gem location (a documented
|
|
987
1115
|
caveat for container / cross-filesystem setups).
|
|
@@ -1237,6 +1365,42 @@ rigor upgrade
|
|
|
1237
1365
|
Until then it prints the current version and notes that upgrade is
|
|
1238
1366
|
queued. Exits `0`.
|
|
1239
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
|
+
|
|
1240
1404
|
## Environment variables
|
|
1241
1405
|
|
|
1242
1406
|
Most behaviour is driven by flags and `.rigor.yml`; a few
|
|
@@ -1268,8 +1432,9 @@ diagnostics about Rigor's own inference cutoffs and memory — see
|
|
|
1268
1432
|
| `64` | Usage error — unknown command, bad flag, malformed argument, or a value in `.rigor.yml` the loader cannot proceed on. |
|
|
1269
1433
|
| `70` | Internal fatal error — `SystemStackError` or `NoMemoryError` inside the analysis; Rigor could not finish the run, so its report on disk is empty rather than clean. |
|
|
1270
1434
|
|
|
1271
|
-
`rigor triage` is the exception: it is advisory and
|
|
1272
|
-
|
|
1435
|
+
`rigor triage` is the exception: it is advisory and exits `0`
|
|
1436
|
+
whenever it runs to completion. A usage error, such as a
|
|
1437
|
+
`--config` that names no file, still exits `64`.
|
|
1273
1438
|
|
|
1274
1439
|
A configuration mistake prints one `rigor:` line naming the key
|
|
1275
1440
|
and nothing else — no backtrace, on every command:
|