rigortype 0.3.7 → 0.3.9
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 +1 -1
- data/data/capability_roles/capability_roles.rbs +36 -0
- data/data/gem_overlay/activesupport/core_ext.rbs +109 -13
- data/docs/handbook/02-everyday-types.md +17 -14
- data/docs/handbook/03-narrowing.md +37 -4
- data/docs/handbook/05-methods-and-blocks.md +1 -1
- data/docs/handbook/06-classes.md +2 -2
- data/docs/handbook/07-rbs-and-extended.md +14 -1
- data/docs/handbook/11-sig-gen.md +96 -15
- data/docs/handbook/README.md +1 -1
- data/docs/handbook/appendix-elixir.md +2 -2
- data/docs/handbook/appendix-go.md +2 -2
- data/docs/handbook/appendix-java-csharp.md +2 -2
- data/docs/handbook/appendix-mypy.md +2 -2
- data/docs/handbook/appendix-phpstan.md +1 -1
- data/docs/handbook/appendix-rust.md +1 -1
- data/docs/handbook/appendix-type-theory.md +4 -4
- data/docs/handbook/appendix-typescript.md +1 -1
- data/docs/llms.txt +2 -0
- data/docs/manual/02-cli-reference.md +39 -4
- data/docs/manual/03-configuration.md +11 -0
- data/docs/manual/04-diagnostics.md +12 -1
- data/docs/manual/07-plugins.md +15 -5
- data/docs/manual/08-skills.md +23 -2
- data/docs/manual/11-ci.md +9 -0
- data/docs/manual/15-type-protection-coverage.md +8 -0
- data/docs/manual/16-rbs-extended-annotations.md +6 -1
- data/docs/manual/18-removing-dead-code.md +10 -8
- data/docs/manual/plugins/rigor-actionpack.md +18 -0
- data/docs/manual/plugins/rigor-activerecord.md +28 -0
- data/docs/manual/plugins/rigor-activesupport-core-ext.md +32 -2
- data/docs/manual/plugins/rigor-rbs-inline.md +42 -1
- data/lib/rigor/analysis/baseline.rb +2 -2
- data/lib/rigor/analysis/check_rules/always_truthy_condition_collector.rb +1 -1
- data/lib/rigor/analysis/check_rules/dead_version_guard_arms.rb +1 -5
- data/lib/rigor/analysis/check_rules/ivar_write_collector.rb +10 -2
- data/lib/rigor/analysis/check_rules/main_pass_collector.rb +1 -1
- data/lib/rigor/analysis/check_rules/published_constant_guard.rb +15 -6
- data/lib/rigor/analysis/check_rules/rule_ids.rb +1 -1
- data/lib/rigor/analysis/check_rules/rule_walk.rb +39 -4
- data/lib/rigor/analysis/check_rules/self_closedness_scanner.rb +1 -1
- data/lib/rigor/analysis/check_rules/shadowed_rescue_collector.rb +1 -1
- data/lib/rigor/analysis/check_rules/unreachable_clause_collector.rb +2 -2
- data/lib/rigor/analysis/check_rules/void_value_use_collector.rb +0 -1
- data/lib/rigor/analysis/check_rules.rb +200 -32
- data/lib/rigor/analysis/crash_signature.rb +69 -13
- data/lib/rigor/analysis/dependency_source_inference/boundary_cross_reporter.rb +1 -1
- data/lib/rigor/analysis/dependency_source_inference/builder.rb +0 -2
- data/lib/rigor/analysis/dependency_source_inference/gem_resolver.rb +0 -2
- data/lib/rigor/analysis/dependency_source_inference/index.rb +5 -5
- data/lib/rigor/analysis/dependency_source_inference/return_type_heuristic.rb +1 -2
- data/lib/rigor/analysis/dependency_source_inference/walker.rb +4 -4
- data/lib/rigor/analysis/effects_cache_probe.rb +3 -4
- data/lib/rigor/analysis/erb_template_detector.rb +1 -2
- data/lib/rigor/analysis/fact_store.rb +6 -1
- data/lib/rigor/analysis/incremental.rb +16 -0
- data/lib/rigor/analysis/incremental_session.rb +100 -29
- data/lib/rigor/analysis/plugin_fact_fingerprint.rb +0 -1
- data/lib/rigor/analysis/reachability/graph.rb +3 -5
- data/lib/rigor/analysis/reachability/plugin_roots.rb +6 -5
- data/lib/rigor/analysis/reachability/project_files.rb +2 -2
- data/lib/rigor/analysis/reachability/scan.rb +5 -5
- data/lib/rigor/analysis/reachability/scan_cache.rb +2 -2
- data/lib/rigor/analysis/reachability/signature_scan.rb +2 -2
- data/lib/rigor/analysis/result.rb +1 -3
- data/lib/rigor/analysis/rule_catalog.rb +4 -1
- data/lib/rigor/analysis/run_cache_key.rb +1 -1
- data/lib/rigor/analysis/run_cache_probe.rb +3 -5
- data/lib/rigor/analysis/runner/buffer_pool_dispatcher.rb +6 -8
- data/lib/rigor/analysis/runner/declaration_position.rb +1 -2
- data/lib/rigor/analysis/runner/diagnostic_aggregator.rb +316 -40
- data/lib/rigor/analysis/runner/effect_annotation_residual_pass.rb +2 -3
- data/lib/rigor/analysis/runner/effect_envelope_pass.rb +9 -10
- data/lib/rigor/analysis/runner/pool_coordinator.rb +430 -77
- data/lib/rigor/analysis/runner/project_pre_passes.rb +12 -6
- data/lib/rigor/analysis/runner/run_snapshots.rb +13 -3
- data/lib/rigor/analysis/runner.rb +200 -43
- data/lib/rigor/analysis/worker_session.rb +36 -12
- data/lib/rigor/bleeding_edge.rb +12 -24
- data/lib/rigor/builtins/hkt_builtins.rb +2 -2
- data/lib/rigor/builtins/imported_refinements.rb +166 -30
- data/lib/rigor/builtins/predefined_constant_refinements.rb +5 -7
- data/lib/rigor/builtins/regex_refinement.rb +4 -4
- data/lib/rigor/builtins/static_return_refinements.rb +5 -6
- data/lib/rigor/cache/annotation_location.rb +70 -0
- data/lib/rigor/cache/descriptor.rb +58 -20
- data/lib/rigor/cache/engine_source.rb +4 -4
- data/lib/rigor/cache/file_digest.rb +9 -1
- data/lib/rigor/cache/incremental_snapshot.rb +40 -6
- data/lib/rigor/cache/rbs_class_ancestor_table.rb +0 -3
- data/lib/rigor/cache/rbs_class_type_param_names.rb +0 -3
- data/lib/rigor/cache/rbs_constant_table.rb +0 -3
- data/lib/rigor/cache/rbs_descriptor.rb +79 -11
- data/lib/rigor/cache/rbs_environment.rb +8 -4
- data/lib/rigor/cache/rbs_environment_marshal_patch.rb +39 -0
- data/lib/rigor/cache/rbs_known_class_names.rb +0 -3
- data/lib/rigor/cache/store.rb +85 -33
- data/lib/rigor/cli/annotate_command.rb +5 -6
- data/lib/rigor/cli/check_command.rb +57 -10
- data/lib/rigor/cli/check_invocation.rb +6 -11
- data/lib/rigor/cli/check_runner_factory.rb +1 -5
- data/lib/rigor/cli/coverage_command.rb +1 -1
- data/lib/rigor/cli/coverage_mutation.rb +12 -3
- data/lib/rigor/cli/coverage_scan.rb +1 -5
- data/lib/rigor/cli/diff_command.rb +1 -1
- data/lib/rigor/cli/doc_links.rb +3 -3
- data/lib/rigor/cli/docs_command.rb +2 -2
- data/lib/rigor/cli/doctor_command.rb +85 -38
- data/lib/rigor/cli/effects_command.rb +2 -2
- data/lib/rigor/cli/effects_diff_renderer.rb +3 -3
- data/lib/rigor/cli/effects_snapshot_command.rb +1 -1
- data/lib/rigor/cli/explain_command.rb +34 -1
- data/lib/rigor/cli/fused_protection_report.rb +7 -1
- data/lib/rigor/cli/lsp_command.rb +1 -1
- data/lib/rigor/cli/mcp_command.rb +1 -1
- data/lib/rigor/cli/measurement_integrity_warning.rb +4 -5
- data/lib/rigor/cli/mutation_fork_scan.rb +6 -6
- data/lib/rigor/cli/mutation_protection_report.rb +7 -1
- data/lib/rigor/cli/plugin_command.rb +1 -1
- data/lib/rigor/cli/plugins_command.rb +2 -1
- data/lib/rigor/cli/prism_colorizer.rb +2 -2
- data/lib/rigor/cli/protection_fork_scan.rb +6 -6
- data/lib/rigor/cli/show_bleedingedge_command.rb +1 -1
- data/lib/rigor/cli/sig_gen_command.rb +31 -2
- data/lib/rigor/cli/skill_command.rb +1 -1
- data/lib/rigor/cli/skill_deep_probe.rb +4 -4
- data/lib/rigor/cli/skill_describe.rb +36 -35
- data/lib/rigor/cli/trace_command.rb +4 -4
- data/lib/rigor/cli/trace_renderer.rb +5 -6
- data/lib/rigor/cli/triage_command.rb +1 -1
- data/lib/rigor/cli/type_of_command.rb +10 -6
- data/lib/rigor/cli/type_scan_command.rb +4 -4
- data/lib/rigor/cli/unused_command.rb +11 -3
- data/lib/rigor/cli/upgrade_command.rb +1 -1
- data/lib/rigor/cli.rb +68 -6
- data/lib/rigor/config_audit.rb +30 -5
- data/lib/rigor/configuration/severity_profile.rb +6 -6
- data/lib/rigor/configuration.rb +43 -4
- data/lib/rigor/effects/attribution.rb +1 -3
- data/lib/rigor/effects/config_envelopes.rb +6 -8
- data/lib/rigor/effects/definition_lines.rb +25 -6
- data/lib/rigor/effects/effect_table.rb +0 -1
- data/lib/rigor/effects/entry_points.rb +0 -2
- data/lib/rigor/effects/envelope_check.rb +8 -8
- data/lib/rigor/effects/envelope_index.rb +5 -8
- data/lib/rigor/effects/framework_units.rb +4 -6
- data/lib/rigor/effects/identity.rb +4 -6
- data/lib/rigor/effects/inline_anchor.rb +7 -7
- data/lib/rigor/effects/label_intent.rb +3 -4
- data/lib/rigor/effects/liskov_check.rb +8 -8
- data/lib/rigor/effects/method_key.rb +1 -1
- data/lib/rigor/effects/plugin_facts.rb +4 -6
- data/lib/rigor/effects/propagator.rb +2 -3
- data/lib/rigor/effects/scanner.rb +1 -1
- data/lib/rigor/effects/signature_sources.rb +3 -5
- data/lib/rigor/effects/snapshot.rb +10 -10
- data/lib/rigor/effects/snapshot_diff.rb +1 -1
- data/lib/rigor/effects/unit_scan.rb +10 -10
- data/lib/rigor/effects/unknown_label_check.rb +3 -8
- data/lib/rigor/effects/unknown_label_report.rb +3 -4
- data/lib/rigor/environment/bundle_sig_discovery.rb +6 -6
- data/lib/rigor/environment/class_registry.rb +3 -1
- data/lib/rigor/environment/failure_slot.rb +28 -0
- data/lib/rigor/environment/installed_gem_set.rb +85 -0
- data/lib/rigor/environment/lockfile_resolver.rb +51 -4
- data/lib/rigor/environment/missing_gem_constant_index.rb +4 -4
- data/lib/rigor/environment/rbs_collection_discovery.rb +5 -5
- data/lib/rigor/environment/rbs_coverage_report.rb +5 -5
- data/lib/rigor/environment/rbs_hierarchy.rb +3 -1
- data/lib/rigor/environment/rbs_loader.rb +613 -113
- data/lib/rigor/environment.rb +189 -27
- data/lib/rigor/flow_contribution/merger.rb +0 -2
- data/lib/rigor/flow_contribution.rb +11 -13
- data/lib/rigor/inference/acceptance.rb +153 -8
- data/lib/rigor/inference/block_parameter_binder.rb +2 -3
- data/lib/rigor/inference/body_fixpoint.rb +5 -5
- data/lib/rigor/inference/budget_trace.rb +1 -5
- data/lib/rigor/inference/captured_locals.rb +2 -3
- data/lib/rigor/inference/closure_escape_analyzer.rb +2 -4
- data/lib/rigor/inference/coverage_scanner.rb +4 -6
- data/lib/rigor/inference/dynamic_origin.rb +1 -1
- data/lib/rigor/inference/element_read_widening.rb +168 -0
- data/lib/rigor/inference/expression_typer.rb +763 -143
- data/lib/rigor/inference/fork_map.rb +5 -7
- data/lib/rigor/inference/hkt_reducer.rb +2 -3
- data/lib/rigor/inference/hkt_registry.rb +19 -10
- data/lib/rigor/inference/hkt_sugar_translator.rb +15 -21
- data/lib/rigor/inference/index_write_widening.rb +1 -5
- data/lib/rigor/inference/macro_block_self_type.rb +1 -4
- data/lib/rigor/inference/method_dispatcher/block_folding.rb +2 -9
- data/lib/rigor/inference/method_dispatcher/cgi_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/constant_folding.rb +305 -19
- data/lib/rigor/inference/method_dispatcher/data_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/file_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/iterator_dispatch.rb +2 -2
- data/lib/rigor/inference/method_dispatcher/json_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/kernel_dispatch.rb +7 -1
- data/lib/rigor/inference/method_dispatcher/math_folding.rb +41 -3
- data/lib/rigor/inference/method_dispatcher/method_folding.rb +2 -5
- data/lib/rigor/inference/method_dispatcher/overload_selector.rb +61 -47
- data/lib/rigor/inference/method_dispatcher/random_folding.rb +82 -0
- data/lib/rigor/inference/method_dispatcher/rbs_dispatch.rb +165 -31
- data/lib/rigor/inference/method_dispatcher/receiver_affinity.rb +25 -4
- data/lib/rigor/inference/method_dispatcher/reduce_folding.rb +2 -8
- data/lib/rigor/inference/method_dispatcher/regexp_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/set_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/shape_dispatch.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/shellwords_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/singleton_mixin_dispatch.rb +1 -2
- data/lib/rigor/inference/method_dispatcher/struct_folding.rb +4 -5
- data/lib/rigor/inference/method_dispatcher/struct_materialization.rb +85 -4
- data/lib/rigor/inference/method_dispatcher/time_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/universal_object_dispatch.rb +1 -2
- data/lib/rigor/inference/method_dispatcher/uri_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher.rb +12 -13
- data/lib/rigor/inference/method_parameter_binder.rb +4 -6
- data/lib/rigor/inference/multi_target_binder.rb +1 -3
- data/lib/rigor/inference/mutation_rejoin.rb +168 -0
- data/lib/rigor/inference/mutation_widening.rb +100 -51
- data/lib/rigor/inference/narrowing.rb +299 -46
- data/lib/rigor/inference/optimistic_origin.rb +1 -7
- data/lib/rigor/inference/origin_lookup.rb +2 -3
- data/lib/rigor/inference/parameter_inference_collector.rb +5 -6
- data/lib/rigor/inference/pre_eval_constants.rb +6 -5
- data/lib/rigor/inference/precision_scanner.rb +3 -4
- data/lib/rigor/inference/project_patched_methods.rb +2 -2
- data/lib/rigor/inference/project_patched_scanner.rb +3 -3
- data/lib/rigor/inference/protection_scanner.rb +1 -2
- data/lib/rigor/inference/range_constant.rb +57 -0
- data/lib/rigor/inference/rbs_type_translator.rb +49 -11
- data/lib/rigor/inference/receiver_alias.rb +3 -3
- data/lib/rigor/inference/refinement_mutation.rb +72 -0
- data/lib/rigor/inference/scope_indexer.rb +688 -151
- data/lib/rigor/inference/statement_evaluator.rb +221 -50
- data/lib/rigor/inference/string_mutation.rb +60 -0
- data/lib/rigor/inference/struct_fold_safety.rb +6 -7
- data/lib/rigor/inference/synthetic_method_index.rb +1 -2
- data/lib/rigor/inference/synthetic_method_scanner.rb +4 -6
- data/lib/rigor/inference/version_guard.rb +28 -21
- data/lib/rigor/inference/void_origin.rb +3 -3
- data/lib/rigor/inference/void_tail_summary.rb +2 -4
- data/lib/rigor/language_server/buffer_table.rb +4 -4
- data/lib/rigor/language_server/completion_provider.rb +1 -1
- data/lib/rigor/language_server/debouncer.rb +1 -1
- data/lib/rigor/language_server/diagnostic_publisher.rb +4 -4
- data/lib/rigor/language_server/document_symbol_provider.rb +1 -1
- data/lib/rigor/language_server/folding_range_provider.rb +1 -1
- data/lib/rigor/language_server/hover_provider.rb +1 -1
- data/lib/rigor/language_server/hover_renderer.rb +2 -2
- data/lib/rigor/language_server/incremental_sync.rb +6 -6
- data/lib/rigor/language_server/project_context.rb +2 -5
- data/lib/rigor/language_server/publish_batcher.rb +2 -2
- data/lib/rigor/language_server/selection_range_provider.rb +2 -2
- data/lib/rigor/language_server/server.rb +9 -9
- data/lib/rigor/language_server/signature_help_provider.rb +1 -1
- data/lib/rigor/language_server/uri.rb +1 -1
- data/lib/rigor/plugin/base.rb +90 -21
- data/lib/rigor/plugin/bundled_catalog.rb +167 -0
- data/lib/rigor/plugin/effect_attribution.rb +7 -7
- data/lib/rigor/plugin/effect_entry_points.rb +3 -3
- data/lib/rigor/plugin/fact_store.rb +6 -6
- data/lib/rigor/plugin/io_boundary.rb +93 -8
- data/lib/rigor/plugin/isolation.rb +29 -6
- data/lib/rigor/plugin/loader.rb +31 -12
- data/lib/rigor/plugin/macro/heredoc_template.rb +1 -1
- data/lib/rigor/plugin/macro/trait_registry.rb +1 -1
- data/lib/rigor/plugin/manifest.rb +23 -1
- data/lib/rigor/plugin/registry.rb +67 -14
- data/lib/rigor/plugin/source_rbs_synthesis_reporter.rb +12 -1
- data/lib/rigor/plugin/trust_policy.rb +2 -4
- data/lib/rigor/plugin/type_node_resolver.rb +3 -3
- data/lib/rigor/plugin_gap_advisory.rb +96 -0
- data/lib/rigor/project_environment.rb +138 -0
- data/lib/rigor/protection/analysis_guard.rb +93 -14
- data/lib/rigor/protection/closure_kill_oracle.rb +67 -23
- data/lib/rigor/protection/dependency_closure.rb +5 -8
- data/lib/rigor/protection/diagnostic_oracle.rb +2 -2
- data/lib/rigor/protection/discovery_seed.rb +11 -11
- data/lib/rigor/protection/kill_signature.rb +2 -4
- data/lib/rigor/protection/measurement_integrity.rb +1 -3
- data/lib/rigor/protection/mutation_cache.rb +6 -9
- data/lib/rigor/protection/mutation_scanner.rb +12 -15
- data/lib/rigor/protection/mutator.rb +2 -1
- data/lib/rigor/protection/test_suite_oracle.rb +5 -5
- data/lib/rigor/rbs_extended/conformance_checker.rb +4 -3
- data/lib/rigor/rbs_extended/envelope_scanner.rb +12 -13
- data/lib/rigor/rbs_extended/hkt_directives.rb +16 -1
- data/lib/rigor/rbs_extended/reporter.rb +122 -16
- data/lib/rigor/rbs_extended.rb +67 -22
- data/lib/rigor/reflection/constant_path.rb +126 -0
- data/lib/rigor/reflection.rb +26 -10
- data/lib/rigor/runtime/jit.rb +6 -8
- data/lib/rigor/scope/discovery_index.rb +30 -0
- data/lib/rigor/scope.rb +203 -4
- data/lib/rigor/sig_gen/generator.rb +181 -102
- data/lib/rigor/sig_gen/layout_index.rb +3 -4
- data/lib/rigor/sig_gen/meta_class_shape.rb +3 -5
- data/lib/rigor/sig_gen/observation_collector.rb +17 -15
- data/lib/rigor/sig_gen/path_mapper.rb +4 -6
- data/lib/rigor/sig_gen/rbs_validity.rb +4 -4
- data/lib/rigor/sig_gen/renderer.rb +17 -11
- data/lib/rigor/sig_gen/skip_reason_catalog.rb +111 -0
- data/lib/rigor/sig_gen/superclass_spelling.rb +27 -0
- data/lib/rigor/sig_gen/type_elaborator.rb +1 -3
- data/lib/rigor/sig_gen/writer.rb +23 -6
- data/lib/rigor/signature_path_audit.rb +153 -6
- data/lib/rigor/source/literals.rb +0 -23
- data/lib/rigor/source/node_children.rb +0 -2
- data/lib/rigor/source/node_locator.rb +5 -11
- data/lib/rigor/source/node_walker.rb +2 -5
- data/lib/rigor/triage/catalogue.rb +1 -3
- data/lib/rigor/triage.rb +3 -5
- data/lib/rigor/type/accepts_result.rb +24 -6
- data/lib/rigor/type/combinator.rb +68 -5
- data/lib/rigor/type/data_class.rb +2 -2
- data/lib/rigor/type/data_instance.rb +4 -4
- data/lib/rigor/type/float_range.rb +128 -0
- data/lib/rigor/type/hash_shape.rb +5 -5
- data/lib/rigor/type/integer_range.rb +13 -8
- data/lib/rigor/type/nominal.rb +8 -2
- data/lib/rigor/type/refined.rb +3 -3
- data/lib/rigor/type/struct_class.rb +3 -3
- data/lib/rigor/type/struct_instance.rb +4 -4
- data/lib/rigor/type.rb +1 -0
- data/lib/rigor/type_node/generic.rb +1 -1
- data/lib/rigor/type_node/range_literal.rb +25 -0
- data/lib/rigor/type_node/resolver_chain.rb +1 -1
- data/lib/rigor/type_node.rb +1 -0
- data/lib/rigor/version.rb +1 -1
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/analyzer.rb +0 -4
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_discoverer.rb +0 -1
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_index.rb +0 -2
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable.rb +1 -0
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/analyzer.rb +0 -4
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_discoverer.rb +3 -5
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_index.rb +1 -4
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer.rb +1 -0
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/analyzer.rb +33 -30
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_discoverer.rb +0 -1
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_index.rb +1 -3
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack.rb +28 -2
- data/plugins/rigor-actionpack/sig/action_controller.rbs +71 -0
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/analyzer.rb +0 -4
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/effects.rb +1 -1
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_discoverer.rb +0 -1
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_index.rb +0 -2
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/recurring_scan.rb +1 -1
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob.rb +1 -0
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_discoverer.rb +3 -4
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_parser.rb +1 -2
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/structure_sql_parser.rb +1 -2
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord.rb +42 -7
- data/plugins/rigor-activerecord/sig/active_record/framework.rbs +123 -0
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage.rb +1 -0
- data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext.rb +9 -2
- data/plugins/rigor-activesupport-core-ext/sig/active_support/core_ext.rbs +119 -14
- data/plugins/rigor-devise/lib/rigor/plugin/devise.rb +1 -0
- data/plugins/rigor-dry-monads/lib/rigor/plugin/dry_monads.rb +1 -0
- data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema/schema_scanner.rb +9 -7
- data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema.rb +7 -3
- data/plugins/rigor-dry-struct/lib/rigor/plugin/dry_struct.rb +1 -0
- data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types/alias_scanner.rb +8 -6
- data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types.rb +11 -7
- data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation/contract_scanner.rb +13 -11
- data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation.rb +9 -4
- data/plugins/rigor-ethon/lib/rigor/plugin/ethon.rb +1 -0
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/analyzer.rb +0 -5
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_discoverer.rb +0 -1
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_index.rb +0 -1
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot.rb +8 -1
- data/plugins/rigor-ffi/lib/rigor/plugin/ffi.rb +36 -4
- data/plugins/rigor-ffi-rzmq/lib/rigor/plugin/ffi_rzmq.rb +1 -0
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql/type_scanner.rb +8 -6
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql.rb +6 -3
- data/plugins/rigor-hanami/lib/rigor/plugin/hanami.rb +1 -0
- data/plugins/rigor-mangrove/lib/rigor/plugin/mangrove.rb +2 -1
- data/plugins/rigor-minitest/lib/rigor/plugin/minitest/assertion_analyzer.rb +0 -3
- data/plugins/rigor-minitest/lib/rigor/plugin/minitest.rb +1 -0
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/analyzer.rb +0 -5
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/authorization_scan.rb +2 -2
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_discoverer.rb +0 -1
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_index.rb +0 -1
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit.rb +1 -0
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/analyzer.rb +0 -12
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_index.rb +1 -3
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_loader.rb +0 -1
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n.rb +1 -0
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/acronyms.rb +5 -5
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/analyzer.rb +1 -10
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/devise_routes.rb +3 -3
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/doorkeeper_routes.rb +2 -2
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/grape_api_discoverer.rb +2 -2
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_discoverer.rb +2 -2
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_table.rb +9 -10
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/routes_parser.rb +2 -3
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes.rb +1 -0
- data/plugins/rigor-railties/lib/rigor/plugin/railties.rb +1 -0
- data/plugins/rigor-rbnacl/lib/rigor/plugin/rbnacl.rb +13 -1
- data/plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline.rb +128 -3
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/analyzer.rb +0 -3
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_scope_index.rb +0 -3
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_type_resolver.rb +1 -5
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/matcher_analyzer.rb +2 -3
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec.rb +1 -0
- data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails/have_http_status_analyzer.rb +0 -3
- data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails.rb +1 -0
- data/plugins/rigor-sassc/lib/rigor/plugin/sassc.rb +1 -0
- data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers/analyzer.rb +1 -9
- data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers.rb +1 -0
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/analyzer.rb +0 -4
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/effects.rb +1 -1
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/schedule_scan.rb +1 -1
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_discoverer.rb +0 -1
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_index.rb +0 -2
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq.rb +1 -0
- data/plugins/rigor-sinatra/lib/rigor/plugin/sinatra.rb +1 -0
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/absurd_recognizer.rb +2 -5
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/assertion_recognizer.rb +1 -4
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog.rb +3 -9
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog_walker.rb +4 -4
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sig_parser.rb +1 -2
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sigil_detector.rb +4 -5
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/type_translator.rb +7 -5
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet.rb +5 -5
- data/plugins/rigor-statesman/lib/rigor/plugin/statesman.rb +1 -0
- data/sig/rigor/analysis/reachability/scan_cache.rbs +12 -0
- data/sig/rigor/cache.rbs +2 -3
- data/sig/rigor/environment.rbs +11 -0
- data/sig/rigor/inference.rbs +3 -10
- data/sig/rigor/plugin/io_boundary.rbs +4 -0
- data/sig/rigor/plugin/manifest.rbs +2 -1
- data/sig/rigor/reflection.rbs +3 -1
- data/sig/rigor/scope.rbs +24 -3
- data/sig/rigor/sig_gen/skip_reason_catalog.rbs +14 -0
- data/sig/rigor/type.rbs +27 -1
- data/sig/rigor.rbs +1 -0
- data/skills/rigor-ask/SKILL.md +8 -6
- data/skills/rigor-plugin-author/references/02-walker-and-types.md +13 -2
- data/skills/rigor-project-init/SKILL.md +6 -3
- data/skills/rigor-project-init/references/02-configure.md +10 -6
- data/skills/rigor-project-init/references/06-agent-contract.md +67 -0
- data/skills/rigor-type-oracle/SKILL.md +228 -0
- data/skills/rigor-type-oracle/references/01-oracle-commands.md +261 -0
- data/skills/rigor-type-oracle/references/02-agents-md-fragment.md +52 -0
- data/skills/rigor-type-oracle/references/03-gap-protocol.md +128 -0
- data/skills/rigor-unused-adjudicate/SKILL.md +8 -5
- metadata +28 -3
- data/lib/rigor/cli/probe_environment.rb +0 -85
- data/sig/rigor/inference/builtins/numeric_catalog.rbs +0 -3
|
@@ -7,9 +7,11 @@ require_relative "../configuration"
|
|
|
7
7
|
require_relative "../config_audit"
|
|
8
8
|
require_relative "../analysis/baseline"
|
|
9
9
|
require_relative "../analysis/result"
|
|
10
|
+
require_relative "../environment/bundle_sig_discovery"
|
|
10
11
|
require_relative "../plugin"
|
|
11
12
|
require_relative "../plugin/loader"
|
|
12
13
|
require_relative "../plugin/services"
|
|
14
|
+
require_relative "../plugin_gap_advisory"
|
|
13
15
|
require_relative "../reflection"
|
|
14
16
|
require_relative "../type/combinator"
|
|
15
17
|
require_relative "check_invocation"
|
|
@@ -33,17 +35,12 @@ module Rigor
|
|
|
33
35
|
CHECK_RBS = "rbs_environment"
|
|
34
36
|
CHECK_PLUGINS = "plugins"
|
|
35
37
|
CHECK_BASELINE = "baseline"
|
|
36
|
-
|
|
38
|
+
CHECK_PLUGIN_GAP = "plugin_gap"
|
|
37
39
|
CHECK_GEMFILE = "gemfile_install"
|
|
38
40
|
CHECK_PLUGIN_SKEW = "plugin_skew"
|
|
41
|
+
CHECK_BUNDLE_LAYOUT = "bundle_layout"
|
|
39
42
|
|
|
40
|
-
|
|
41
|
-
RAILS_PLUGIN_MARKERS = %w[
|
|
42
|
-
rigor-activerecord rigor-actionpack rigor-actionmailer rigor-activejob
|
|
43
|
-
rigor-rails-routes rigor-rails-i18n rigor-actioncable rigor-activestorage rigor-rails
|
|
44
|
-
].freeze
|
|
45
|
-
|
|
46
|
-
# @return [Integer] CLI exit status.
|
|
43
|
+
# @return CLI exit status.
|
|
47
44
|
def run
|
|
48
45
|
options = parse_options
|
|
49
46
|
configuration = Configuration.load(options.fetch(:config))
|
|
@@ -70,8 +67,8 @@ module Rigor
|
|
|
70
67
|
# 5. Baseline drift check.
|
|
71
68
|
findings.concat(check_baseline(configuration, result))
|
|
72
69
|
|
|
73
|
-
# 6.
|
|
74
|
-
findings.concat(
|
|
70
|
+
# 6. Gems locked that a bundled plugin models, with that plugin not enabled (ADR-96 WD2).
|
|
71
|
+
findings.concat(check_plugin_gap(configuration))
|
|
75
72
|
|
|
76
73
|
# 7. Rigor itself resolved as a project dependency.
|
|
77
74
|
findings.concat(check_gemfile_install)
|
|
@@ -79,6 +76,9 @@ module Rigor
|
|
|
79
76
|
# 8. A bundled plugin loaded from a different rigortype installation than the engine (#194 slice 3).
|
|
80
77
|
findings.concat(check_plugin_skew(registry))
|
|
81
78
|
|
|
79
|
+
# 9. The project's gems are installed somewhere Rigor cannot see (ADR-25 carry-over).
|
|
80
|
+
findings.concat(check_bundle_layout(configuration))
|
|
81
|
+
|
|
82
82
|
report(findings, options.fetch(:format))
|
|
83
83
|
findings.any? { |f| f[:status] == :fail } ? 1 : 0
|
|
84
84
|
rescue OptionParser::InvalidArgument => e
|
|
@@ -249,6 +249,46 @@ module Rigor
|
|
|
249
249
|
File.expand_path(path)
|
|
250
250
|
end
|
|
251
251
|
|
|
252
|
+
# ADR-25 carry-over — the plain `bundle install` layout. {Environment::BundleSigDiscovery} detects a
|
|
253
|
+
# bundle root only from paths the PROJECT records: `.bundle/config`'s `BUNDLE_PATH`, an in-tree
|
|
254
|
+
# `vendor/bundle`, or the user-global Bundler config. The default layout records none of those — the
|
|
255
|
+
# gems live in the active Ruby's `GEM_HOME`, which is a property of the project's toolchain, and
|
|
256
|
+
# ADR-27 keeps Rigor from running that toolchain to ask. So detection is not a bounded probe Rigor can
|
|
257
|
+
# add; what it CAN do is stop the state being silent. Without this the user sees gem-shipped `sig/`
|
|
258
|
+
# simply not taking effect, with nothing anywhere naming the reason.
|
|
259
|
+
#
|
|
260
|
+
# Warn, never fail: the layout is the Ruby default and is perfectly correct — only ~3% of gems ship
|
|
261
|
+
# `sig/` at all, so most projects lose nothing by it.
|
|
262
|
+
def check_bundle_layout(configuration)
|
|
263
|
+
return [] unless File.file?(File.join(Dir.pwd, "Gemfile.lock"))
|
|
264
|
+
return [] if resolved_bundle_root(configuration)
|
|
265
|
+
|
|
266
|
+
[
|
|
267
|
+
{
|
|
268
|
+
check: CHECK_BUNDLE_LAYOUT,
|
|
269
|
+
status: :warn,
|
|
270
|
+
message: "Gems are installed in the active Ruby's default gem home, which Rigor cannot locate — " \
|
|
271
|
+
"no gem-shipped `sig/` is being discovered",
|
|
272
|
+
hint: "Rigor reads your project as data and never runs its toolchain, so it can only find a " \
|
|
273
|
+
"bundle whose location the project records (`.bundle/config`'s `BUNDLE_PATH`, an in-tree " \
|
|
274
|
+
"`vendor/bundle`, or your global Bundler config). Point it at the install root with " \
|
|
275
|
+
"`bundler.bundle_path:` in `.rigor.yml`, run `bundle config set --local path vendor/bundle` " \
|
|
276
|
+
"and reinstall, or supply signatures with `rbs collection install` instead."
|
|
277
|
+
}
|
|
278
|
+
]
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
def resolved_bundle_root(configuration)
|
|
282
|
+
Environment::BundleSigDiscovery.resolve_bundle_path(
|
|
283
|
+
bundle_path: configuration.bundler_bundle_path,
|
|
284
|
+
project_root: Dir.pwd,
|
|
285
|
+
auto_detect: configuration.bundler_auto_detect
|
|
286
|
+
)
|
|
287
|
+
rescue StandardError
|
|
288
|
+
# A doctor check must never be the thing that breaks the command it is diagnosing.
|
|
289
|
+
nil
|
|
290
|
+
end
|
|
291
|
+
|
|
252
292
|
def check_baseline(configuration, result)
|
|
253
293
|
path = configuration.baseline_path
|
|
254
294
|
return [] if path.nil? || !File.exist?(path)
|
|
@@ -287,38 +327,45 @@ module Rigor
|
|
|
287
327
|
parts.join(", ")
|
|
288
328
|
end
|
|
289
329
|
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
330
|
+
# ADR-96 WD2 — the plugin-gap advisory, read off each bundled plugin's `target_gems:` rather than the
|
|
331
|
+
# Rails-only tables it replaces. Per plugin, so a Rails app that enabled only `rigor-activerecord` now
|
|
332
|
+
# hears about the other seven; `:warn`, because declining a plugin is a legitimate choice and must not
|
|
333
|
+
# fail the command forever. The one `:fail` is today's behaviour generalised: the project depends on
|
|
334
|
+
# gems Rigor models and enables none of the plugins that model them, which is genuinely unconfigured.
|
|
335
|
+
# Both branches read the lockfile's `DEPENDENCIES` section, never its resolved graph: a transitive
|
|
336
|
+
# `minitest` or `i18n` rides along in nearly every Rails lock, and failing `doctor` on one would fail a
|
|
337
|
+
# correctly configured project.
|
|
338
|
+
def check_plugin_gap(configuration)
|
|
339
|
+
return [] if Configuration.discover.nil?
|
|
340
|
+
|
|
341
|
+
gaps = PluginGapAdvisory.gaps(project_root: Dir.pwd, plugins: configuration.plugins)
|
|
342
|
+
return [] if gaps.empty?
|
|
343
|
+
|
|
344
|
+
if PluginGapAdvisory.unconfigured?(project_root: Dir.pwd, plugins: configuration.plugins)
|
|
345
|
+
[unconfigured_plugin_finding(gaps)]
|
|
346
|
+
else
|
|
347
|
+
gaps.map { |gap| plugin_gap_finding(gap) }
|
|
348
|
+
end
|
|
302
349
|
end
|
|
303
350
|
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
return false unless File.file?(lock) && file_mentions_any?(lock, RAILS_LOCK_MARKERS)
|
|
313
|
-
|
|
314
|
-
!file_mentions_any?(config_path, RAILS_PLUGIN_MARKERS)
|
|
351
|
+
def unconfigured_plugin_finding(gaps)
|
|
352
|
+
{
|
|
353
|
+
check: CHECK_PLUGIN_GAP,
|
|
354
|
+
status: :fail,
|
|
355
|
+
message: "#{gaps.size} bundled plugin(s) model gems this project depends on and none is enabled " \
|
|
356
|
+
"(#{gaps.map(&:plugin_gem).join(', ')})",
|
|
357
|
+
hint: "Add the plugins for your stack to `.rigor.yml` `plugins:` so framework calls resolve."
|
|
358
|
+
}
|
|
315
359
|
end
|
|
316
360
|
|
|
317
|
-
def
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
361
|
+
def plugin_gap_finding(gap)
|
|
362
|
+
{
|
|
363
|
+
check: CHECK_PLUGIN_GAP,
|
|
364
|
+
status: :warn,
|
|
365
|
+
message: "#{gap.locked_gems.join(', ')} #{gap.locked_gems.one? ? 'is a dependency' : 'are dependencies'} " \
|
|
366
|
+
"of this project and #{gap.plugin_gem} models it, but it is not enabled",
|
|
367
|
+
hint: "Add `#{gap.plugin_gem}` to `.rigor.yml` `plugins:`, or leave it out deliberately."
|
|
368
|
+
}
|
|
322
369
|
end
|
|
323
370
|
|
|
324
371
|
# Rigor is a tool, not a library (ADR-27): resolving it as one of the project's own dependencies pins the
|
|
@@ -41,7 +41,7 @@ module Rigor
|
|
|
41
41
|
class EffectsCommand < Command
|
|
42
42
|
USAGE = "Usage: rigor effects [options] [paths]"
|
|
43
43
|
|
|
44
|
-
# @return
|
|
44
|
+
# @return CLI exit status: 0 on success, 1 on `check` drift, 64 on a usage error.
|
|
45
45
|
def run
|
|
46
46
|
verb = @argv.first
|
|
47
47
|
return run_verb(verb) if EffectsSnapshotCommand::VERBS.include?(verb)
|
|
@@ -231,7 +231,7 @@ module Rigor
|
|
|
231
231
|
# project does — still analyses it. Inside a project the argument is already under `paths:` and the
|
|
232
232
|
# union is the configured set unchanged.
|
|
233
233
|
#
|
|
234
|
-
# @return
|
|
234
|
+
# @return the table, and which
|
|
235
235
|
# file each unit was defined in — the map {EffectsReport} needs to answer a path argument.
|
|
236
236
|
def analyze(configuration, scope)
|
|
237
237
|
require_relative "../analysis/runner"
|
|
@@ -50,12 +50,12 @@ module Rigor
|
|
|
50
50
|
REGENERATION_CLOSING_LINE = "Run `rigor effects update` to regenerate the record under the current " \
|
|
51
51
|
"rules."
|
|
52
52
|
|
|
53
|
-
# @param sources
|
|
53
|
+
# @param sources — `Runner#effect_sources` — where each unit is defined.
|
|
54
54
|
# A drift row names `file:line` so a reviewer does not have to search for the method (#435). The
|
|
55
55
|
# file rides the cached summary entry and is free; the line is resolved by parsing the row's own
|
|
56
56
|
# file ({Effects::DefinitionLines}), which is why a fresh report — no rows — still parses nothing
|
|
57
57
|
# and the whole-project parse ADR-104 removed from this command stays removed.
|
|
58
|
-
# @param lines
|
|
58
|
+
# @param lines — seam for the specs; the default parses on demand.
|
|
59
59
|
def initialize(out:, path:, sources: nil, lines: Effects::DefinitionLines.new)
|
|
60
60
|
@out = out
|
|
61
61
|
@path = path
|
|
@@ -121,7 +121,7 @@ module Rigor
|
|
|
121
121
|
# method that no longer exists was not defined by it. Such a row renders exactly as it did before
|
|
122
122
|
# this suffix existed.
|
|
123
123
|
#
|
|
124
|
-
# @return
|
|
124
|
+
# @return `[relative path, line]` per file, the line nil when that
|
|
125
125
|
# file spells the key with no `def` — an accessor, or a definition the nesting cannot name.
|
|
126
126
|
def sources_of(symbol)
|
|
127
127
|
Array(@sources[symbol]).map do |path|
|
|
@@ -51,7 +51,7 @@ module Rigor
|
|
|
51
51
|
@verb = verb
|
|
52
52
|
end
|
|
53
53
|
|
|
54
|
-
# @return
|
|
54
|
+
# @return 0 fresh / written, 1 on drift under `check`, 64 on a usage error.
|
|
55
55
|
def run
|
|
56
56
|
options = parse_options
|
|
57
57
|
return usage_error("unsupported format: #{options.fetch(:format)}") unless
|
|
@@ -4,6 +4,7 @@ require "json"
|
|
|
4
4
|
require "optionparser"
|
|
5
5
|
|
|
6
6
|
require_relative "../analysis/rule_catalog"
|
|
7
|
+
require_relative "../sig_gen/skip_reason_catalog"
|
|
7
8
|
require_relative "command"
|
|
8
9
|
|
|
9
10
|
module Rigor
|
|
@@ -18,7 +19,7 @@ module Rigor
|
|
|
18
19
|
class ExplainCommand < Command
|
|
19
20
|
USAGE = "Usage: rigor explain [options] [<rule>]"
|
|
20
21
|
|
|
21
|
-
# @return
|
|
22
|
+
# @return CLI exit status.
|
|
22
23
|
def run
|
|
23
24
|
options = parse_options
|
|
24
25
|
|
|
@@ -28,6 +29,12 @@ module Rigor
|
|
|
28
29
|
end
|
|
29
30
|
|
|
30
31
|
token = @argv.shift
|
|
32
|
+
skip_reason = SigGen::SkipReasonCatalog.resolve(token)
|
|
33
|
+
if skip_reason
|
|
34
|
+
render_skip_reason(skip_reason, options.fetch(:format))
|
|
35
|
+
return 0
|
|
36
|
+
end
|
|
37
|
+
|
|
31
38
|
entries = Analysis::RuleCatalog.resolve(token)
|
|
32
39
|
if entries.empty?
|
|
33
40
|
@err.puts("Unknown rule: #{token}")
|
|
@@ -68,6 +75,32 @@ module Rigor
|
|
|
68
75
|
@out.puts("")
|
|
69
76
|
@out.puts("Run `rigor explain <rule>` for the full description.")
|
|
70
77
|
@out.puts("Family wildcards (`call`, `flow`, `assert`, `dump`, `def`) print every rule under that prefix.")
|
|
78
|
+
@out.puts("")
|
|
79
|
+
@out.puts("`rigor sig-gen` skip reasons:")
|
|
80
|
+
@out.puts("")
|
|
81
|
+
SigGen::SkipReasonCatalog.all.each do |entry|
|
|
82
|
+
@out.puts(" #{entry.id.ljust(33)} #{entry.summary}")
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def render_skip_reason(entry, format)
|
|
87
|
+
if format == "json"
|
|
88
|
+
@out.puts(JSON.pretty_generate(entry.to_h))
|
|
89
|
+
return
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
@out.puts(entry.id)
|
|
93
|
+
@out.puts("=" * entry.id.length)
|
|
94
|
+
@out.puts("")
|
|
95
|
+
@out.puts(entry.summary)
|
|
96
|
+
@out.puts("")
|
|
97
|
+
@out.puts("A `rigor sig-gen` skip reason, not a diagnostic rule: it reports a signature that was NOT")
|
|
98
|
+
@out.puts("written, so it has no severity and nothing to suppress.")
|
|
99
|
+
@out.puts("")
|
|
100
|
+
@out.puts(entry.explanation)
|
|
101
|
+
@out.puts("")
|
|
102
|
+
@out.puts("What to do:")
|
|
103
|
+
@out.puts(" #{entry.next_step}")
|
|
71
104
|
end
|
|
72
105
|
|
|
73
106
|
def render_entries(entries, format)
|
|
@@ -12,7 +12,13 @@ module Rigor
|
|
|
12
12
|
# Framing (ADR-63 / ADR-62 Criterion A, extended): the payload is the **attribution** — which protection axis is
|
|
13
13
|
# missing — never raw survival. An unprotected site is "add protection here", never "your code is broken".
|
|
14
14
|
# `harness_errors` (#264) — see {Rigor::CLI::FileEffectiveness}; defaults to 0 for the same reason.
|
|
15
|
-
|
|
15
|
+
# A `class ... < Data.define(...)` body, not the `Data.define(...) do ... end` shorthand: Steep
|
|
16
|
+
# resolves a `def` inside the shorthand block against the *lexically enclosing* class (here,
|
|
17
|
+
# `Rigor::CLI`, which declares its own differently-shaped `initialize`) rather than the anonymous
|
|
18
|
+
# Data subclass being defined — a `sig/` declaration for `FusedFileProtection` cannot fix this,
|
|
19
|
+
# since the misattribution happens before any signature is consulted. The explicit `class` keyword
|
|
20
|
+
# is a real namespace boundary Steep's block walker respects; behaviour is identical either way.
|
|
21
|
+
class FusedFileProtection < Data.define(:path, :type_killed, :test_killed, :unprotected, :ratio, :harness_errors)
|
|
16
22
|
def initialize(path:, type_killed:, test_killed:, unprotected:, ratio:, harness_errors: 0)
|
|
17
23
|
super
|
|
18
24
|
end
|
|
@@ -20,15 +20,14 @@ module Rigor
|
|
|
20
20
|
module MeasurementIntegrityWarning
|
|
21
21
|
module_function
|
|
22
22
|
|
|
23
|
-
# @param report
|
|
24
|
-
# @param err
|
|
25
|
-
# @param floor
|
|
26
|
-
# @return [void]
|
|
23
|
+
# @param report — both expose the two counts.
|
|
24
|
+
# @param err — the stream to warn on.
|
|
25
|
+
# @param floor — {CoverageMutation::HARNESS_ERROR_WARN_FLOOR}.
|
|
27
26
|
def emit(report, err:, floor:)
|
|
28
27
|
lines_for(report, floor: floor).each { |line| err.puts(line) }
|
|
29
28
|
end
|
|
30
29
|
|
|
31
|
-
# @return
|
|
30
|
+
# @return the warnings this report earns, widest consequence first.
|
|
32
31
|
def lines_for(report, floor:)
|
|
33
32
|
lines = []
|
|
34
33
|
unmeasured = report.respond_to?(:unmeasured_files) ? report.unmeasured_files : 0 # see CoverageCommand
|
|
@@ -32,12 +32,12 @@ module Rigor
|
|
|
32
32
|
# reliably marshalable, and the accumulator only needs the count).
|
|
33
33
|
ParseError = Data.define(:count)
|
|
34
34
|
|
|
35
|
-
# @param paths
|
|
36
|
-
# @param scanner
|
|
37
|
-
# @param environment
|
|
38
|
-
# @param configuration
|
|
39
|
-
# @param workers
|
|
40
|
-
# @return
|
|
35
|
+
# @param paths — the files to measure, in caller order.
|
|
36
|
+
# @param scanner — built on the parent; COW-inherited by workers.
|
|
37
|
+
# @param environment — the scanner's environment, prewarmed here before forking.
|
|
38
|
+
# @param configuration — for the Prism `target_ruby` version.
|
|
39
|
+
# @param workers — resolved worker count (≤1 → sequential).
|
|
40
|
+
# @return one entry per path.
|
|
41
41
|
def run(paths:, scanner:, environment:, configuration:, workers:)
|
|
42
42
|
# Force the full RBS load on the parent so children copy-on-write inherit a warm environment rather
|
|
43
43
|
# than each rebuilding it after the fork. A no-op on the sequential path but cheap.
|
|
@@ -14,7 +14,13 @@ module Rigor
|
|
|
14
14
|
# `harness_errors` (#264) — mutants where the harness itself raised (a rescued failure), distinguished from
|
|
15
15
|
# a parse-invalid mutant. Defaults to 0 so existing call sites keep constructing a `FileEffectiveness`
|
|
16
16
|
# without the new keyword.
|
|
17
|
-
|
|
17
|
+
# A `class ... < Data.define(...)` body, not the `Data.define(...) do ... end` shorthand: Steep
|
|
18
|
+
# resolves a `def` inside the shorthand block against the *lexically enclosing* class (here,
|
|
19
|
+
# `Rigor::CLI`, which declares its own differently-shaped `initialize`) rather than the anonymous
|
|
20
|
+
# Data subclass being defined — a `sig/` declaration for `FileEffectiveness` cannot fix this,
|
|
21
|
+
# since the misattribution happens before any signature is consulted. The explicit `class` keyword
|
|
22
|
+
# is a real namespace boundary Steep's block walker respects; behaviour is identical either way.
|
|
23
|
+
class FileEffectiveness < Data.define(:path, :killed, :survived, :ratio, :harness_errors)
|
|
18
24
|
def initialize(path:, killed:, survived:, ratio:, harness_errors: 0)
|
|
19
25
|
super
|
|
20
26
|
end
|
|
@@ -62,7 +62,7 @@ module Rigor
|
|
|
62
62
|
class PluginsCommand < Command # rubocop:disable Metrics/ClassLength
|
|
63
63
|
USAGE = "Usage: rigor plugins [options]"
|
|
64
64
|
|
|
65
|
-
# @return
|
|
65
|
+
# @return CLI exit status.
|
|
66
66
|
def run
|
|
67
67
|
options = parse_options
|
|
68
68
|
config_path = options.fetch(:config) || Configuration.discover
|
|
@@ -143,6 +143,7 @@ module Rigor
|
|
|
143
143
|
required_by = loaded_ids & Plugin::Inflector::CONSUMER_PLUGIN_IDS
|
|
144
144
|
return nil if required_by.empty?
|
|
145
145
|
|
|
146
|
+
Plugin::Isolation.configured_strategy = configuration.plugins_isolation
|
|
146
147
|
Plugin::Isolation.target_bundle_root ||= Environment::BundleSigDiscovery.resolve_bundle_path(
|
|
147
148
|
bundle_path: configuration.bundler_bundle_path,
|
|
148
149
|
project_root: Dir.pwd,
|
|
@@ -35,8 +35,8 @@ module Rigor
|
|
|
35
35
|
|
|
36
36
|
VARIABLE_TOKENS = %i[INSTANCE_VARIABLE CLASS_VARIABLE GLOBAL_VARIABLE].freeze
|
|
37
37
|
|
|
38
|
-
# @param source
|
|
39
|
-
# @return
|
|
38
|
+
# @param source — Ruby source.
|
|
39
|
+
# @return the source with ANSI colour escapes, or
|
|
40
40
|
# the input unchanged when lexing surfaces an error.
|
|
41
41
|
def colorize(source)
|
|
42
42
|
# Sources read under a POSIX locale arrive tagged US-ASCII even when they carry UTF-8 bytes; retag so the token
|
|
@@ -23,12 +23,12 @@ module Rigor
|
|
|
23
23
|
# reliably marshalable, and the accumulator only needs the count).
|
|
24
24
|
ParseError = Data.define(:count)
|
|
25
25
|
|
|
26
|
-
# @param paths
|
|
27
|
-
# @param scanner
|
|
28
|
-
# @param environment
|
|
29
|
-
# @param configuration
|
|
30
|
-
# @param workers
|
|
31
|
-
# @return
|
|
26
|
+
# @param paths — the files to scan, in caller order.
|
|
27
|
+
# @param scanner — built on the parent; COW-inherited by workers.
|
|
28
|
+
# @param environment — the scanner's environment, prewarmed here before forking.
|
|
29
|
+
# @param configuration — for the Prism `target_ruby` version.
|
|
30
|
+
# @param workers — resolved worker count (≤1 → sequential).
|
|
31
|
+
# @return one entry per path.
|
|
32
32
|
def run(paths:, scanner:, environment:, configuration:, workers:)
|
|
33
33
|
# Force the full RBS load on the parent so children copy-on-write inherit a warm environment rather
|
|
34
34
|
# than each rebuilding it after the fork (mirrors the check fork pool's parent-side prewarm). A
|
|
@@ -21,7 +21,7 @@ module Rigor
|
|
|
21
21
|
class ShowBleedingedgeCommand < Command
|
|
22
22
|
USAGE = "Usage: rigor show-bleedingedge [options]"
|
|
23
23
|
|
|
24
|
-
# @return
|
|
24
|
+
# @return CLI exit status.
|
|
25
25
|
def run
|
|
26
26
|
options = parse_options
|
|
27
27
|
configuration = load_configuration(options)
|
|
@@ -33,7 +33,13 @@ module Rigor
|
|
|
33
33
|
VALID_PARAM_POLICIES = %w[untyped observed observed-strict].freeze
|
|
34
34
|
VALID_FORMATS = %w[text json].freeze
|
|
35
35
|
|
|
36
|
-
#
|
|
36
|
+
# The skip reasons {#report_skipped} counts. The two left out each have a detailed report of their own
|
|
37
|
+
# ({#report_unrenderable}, {#report_unresolvable_superclasses}), so a method never shows up in two tallies.
|
|
38
|
+
SUMMARISED_SKIP_REASONS = (SigGen::Classification::SKIP_DIAGNOSTIC_IDS.keys -
|
|
39
|
+
%i[unrenderable_rbs unresolvable_superclass]).freeze
|
|
40
|
+
private_constant :SUMMARISED_SKIP_REASONS
|
|
41
|
+
|
|
42
|
+
# @return CLI exit status.
|
|
37
43
|
def run
|
|
38
44
|
options = parse_options
|
|
39
45
|
return CLI::EXIT_USAGE if options.nil?
|
|
@@ -54,6 +60,7 @@ module Rigor
|
|
|
54
60
|
dispatch_print_or_diff(candidates, mode, options)
|
|
55
61
|
0
|
|
56
62
|
end
|
|
63
|
+
report_skipped(candidates, options)
|
|
57
64
|
report_unrenderable(generator.unrenderable)
|
|
58
65
|
report_unresolvable_superclasses(generator.unresolvable_superclasses)
|
|
59
66
|
status
|
|
@@ -61,6 +68,28 @@ module Rigor
|
|
|
61
68
|
|
|
62
69
|
private
|
|
63
70
|
|
|
71
|
+
# Issue #778 — one stderr line per run saying how many methods the generator declined and why, so a
|
|
72
|
+
# method missing from the output is never a silent absence. Text mode only: under `--format=json` every
|
|
73
|
+
# skipped row is already in the payload with its `skip_reason`, and stderr stays clean for the consumer.
|
|
74
|
+
# Per-method lines would be noise at project scale; the JSON payload is where each one is named.
|
|
75
|
+
def report_skipped(candidates, options)
|
|
76
|
+
return unless options.fetch(:format) == "text"
|
|
77
|
+
|
|
78
|
+
counts = candidates.each_with_object(Hash.new(0)) do |candidate, acc|
|
|
79
|
+
next unless candidate.classification == SigGen::Classification::SKIPPED
|
|
80
|
+
next unless SUMMARISED_SKIP_REASONS.include?(candidate.skip_reason)
|
|
81
|
+
|
|
82
|
+
acc[candidate.skip_reason] += 1
|
|
83
|
+
end
|
|
84
|
+
return if counts.empty?
|
|
85
|
+
|
|
86
|
+
breakdown = counts.map { |reason, n| "#{SigGen::Classification::SKIP_DIAGNOSTIC_IDS.fetch(reason)}: #{n}" }
|
|
87
|
+
@err.puts(
|
|
88
|
+
"rigor sig-gen: skipped #{counts.values.sum} method(s) it could not type or would not overwrite " \
|
|
89
|
+
"(#{breakdown.join(', ')}). Run with --format=json to see each one with its skip_reason."
|
|
90
|
+
)
|
|
91
|
+
end
|
|
92
|
+
|
|
64
93
|
# A method whose rendered RBS does not parse is a Rigor rendering defect, not a fact about the user's
|
|
65
94
|
# code — the generator skipped it (so the rest of the signatures are still usable and still valid), but
|
|
66
95
|
# staying silent would leave the user with a quietly incomplete `sig/` and us with an unreported bug.
|
|
@@ -106,7 +135,7 @@ module Rigor
|
|
|
106
135
|
)
|
|
107
136
|
end
|
|
108
137
|
|
|
109
|
-
# @return
|
|
138
|
+
# @return exit status — non-zero when a file the user asked to write could not be written.
|
|
110
139
|
def dispatch_write(candidates, configuration, options)
|
|
111
140
|
layout_index = SigGen::LayoutIndex.new(signature_paths: configuration.signature_paths)
|
|
112
141
|
path_mapper = SigGen::PathMapper.new(configuration: configuration, layout_index: layout_index)
|
|
@@ -37,22 +37,22 @@ module Rigor
|
|
|
37
37
|
# that could not run is NOT a clean check and the report must never let it read as one.
|
|
38
38
|
# - `route` / `reason` — the headline override, or nil to leave the presence-only recommendation standing.
|
|
39
39
|
Report = Data.define(:status, :detail, :route, :reason) do
|
|
40
|
-
# @return
|
|
40
|
+
# @return true when the check did not complete — the caller must then say so rather than let the
|
|
41
41
|
# fallback recommendation read as an all-clear.
|
|
42
42
|
def failed?
|
|
43
43
|
status == :error
|
|
44
44
|
end
|
|
45
45
|
end
|
|
46
46
|
|
|
47
|
-
# @param config
|
|
48
|
-
# @param root
|
|
47
|
+
# @param config — the config filename the presence probe found, relative to `root`.
|
|
48
|
+
# @param root — project root (the analysis itself resolves paths against the process cwd, as
|
|
49
49
|
# `rigor check` does).
|
|
50
50
|
def initialize(config:, root: Dir.pwd)
|
|
51
51
|
@config = config
|
|
52
52
|
@root = root
|
|
53
53
|
end
|
|
54
54
|
|
|
55
|
-
# @return
|
|
55
|
+
# @return never raises — every failure degrades to a `:error`/`:skipped` report whose `route` is nil,
|
|
56
56
|
# leaving the presence-only headline in charge.
|
|
57
57
|
def run
|
|
58
58
|
if @config.nil?
|