rigortype 0.3.8 → 0.4.0
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/capability_roles/capability_roles.rbs +36 -0
- data/data/core_overlay/enumerable.rbs +51 -0
- data/data/core_overlay/enumerator.rbs +84 -0
- data/data/core_overlay/hash_rbs3.rbs +41 -0
- data/data/core_overlay/process.rbs +40 -0
- data/data/core_overlay/string_io.rbs +33 -0
- data/data/effects/core.yml +3 -3
- data/data/gem_overlay/activesupport/core_ext.rbs +236 -17
- data/docs/handbook/02-everyday-types.md +17 -14
- data/docs/handbook/03-narrowing.md +132 -14
- data/docs/handbook/04-tuples-and-shapes.md +8 -6
- 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 +19 -1
- data/docs/handbook/10-sorbet.md +9 -10
- data/docs/handbook/11-sig-gen.md +525 -13
- 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 +95 -6
- data/docs/manual/03-configuration.md +18 -0
- data/docs/manual/04-diagnostics.md +15 -0
- data/docs/manual/07-plugins.md +15 -5
- data/docs/manual/08-skills.md +23 -2
- data/docs/manual/10-mcp-server.md +3 -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 +46 -8
- data/docs/manual/18-removing-dead-code.md +10 -8
- data/docs/manual/19-effect-labels.md +10 -0
- data/docs/manual/plugins/README.md +7 -0
- data/docs/manual/plugins/rigor-actioncable.md +8 -1
- data/docs/manual/plugins/rigor-actionmailer.md +7 -0
- data/docs/manual/plugins/rigor-actionpack.md +261 -0
- data/docs/manual/plugins/rigor-active-model-serializers.md +153 -0
- data/docs/manual/plugins/rigor-activejob.md +7 -0
- data/docs/manual/plugins/rigor-activerecord.md +138 -4
- data/docs/manual/plugins/rigor-activestorage.md +8 -1
- data/docs/manual/plugins/rigor-activesupport-core-ext.md +43 -7
- data/docs/manual/plugins/rigor-grape.md +106 -0
- data/docs/manual/plugins/rigor-graphql.md +23 -2
- data/docs/manual/plugins/rigor-pundit.md +8 -1
- data/docs/manual/plugins/rigor-rails-i18n.md +10 -5
- data/docs/manual/plugins/rigor-rails-routes.md +7 -0
- data/docs/manual/plugins/rigor-rbs-inline.md +229 -1
- data/docs/manual/plugins/rigor-sidekiq.md +8 -1
- data/docs/manual/plugins/rigor-sorbet.md +21 -5
- data/exe/rigor +19 -4
- data/lib/rigor/analysis/baseline.rb +3 -3
- 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/declaration_sourced_guard.rb +167 -2
- data/lib/rigor/analysis/check_rules/ivar_write_collector.rb +10 -2
- data/lib/rigor/analysis/check_rules/lexical_method_sites.rb +189 -0
- data/lib/rigor/analysis/check_rules/main_pass_collector.rb +6 -4
- data/lib/rigor/analysis/check_rules/published_constant_guard.rb +15 -6
- data/lib/rigor/analysis/check_rules/rule_ids.rb +21 -6
- data/lib/rigor/analysis/check_rules/rule_walk.rb +41 -5
- 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/source_arity.rb +323 -0
- data/lib/rigor/analysis/check_rules/special_global_setters.rb +146 -0
- data/lib/rigor/analysis/check_rules/unreachable_clause_collector.rb +38 -4
- data/lib/rigor/analysis/check_rules/void_value_use_collector.rb +0 -1
- data/lib/rigor/analysis/check_rules.rb +718 -79
- data/lib/rigor/analysis/crash_signature.rb +8 -24
- data/lib/rigor/analysis/dependency_recorder.rb +23 -0
- 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 +15 -1
- data/lib/rigor/analysis/incremental.rb +42 -0
- data/lib/rigor/analysis/incremental_session.rb +117 -26
- data/lib/rigor/analysis/plugin_fact_fingerprint.rb +0 -1
- data/lib/rigor/analysis/project_scan.rb +11 -1
- data/lib/rigor/analysis/reachability/graph.rb +3 -5
- data/lib/rigor/analysis/reachability/plugin_roots.rb +5 -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 +3 -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 +131 -1
- data/lib/rigor/analysis/run_cache_key.rb +21 -12
- 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 +340 -33
- data/lib/rigor/analysis/runner/effect_annotation_residual_pass.rb +2 -3
- data/lib/rigor/analysis/runner/effect_envelope_pass.rb +18 -14
- data/lib/rigor/analysis/runner/pool_coordinator.rb +357 -97
- data/lib/rigor/analysis/runner/project_pre_passes.rb +38 -13
- data/lib/rigor/analysis/runner/run_snapshots.rb +6 -1
- data/lib/rigor/analysis/runner.rb +407 -51
- data/lib/rigor/analysis/template_unit_collector.rb +303 -0
- data/lib/rigor/analysis/template_unit_paths.rb +91 -0
- data/lib/rigor/analysis/template_unit_positions.rb +293 -0
- data/lib/rigor/analysis/template_units.rb +399 -0
- data/lib/rigor/analysis/worker_session.rb +62 -20
- data/lib/rigor/bleeding_edge.rb +10 -24
- data/lib/rigor/builtins/hkt_builtins.rb +3 -2
- data/lib/rigor/builtins/imported_refinements.rb +159 -21
- data/lib/rigor/builtins/predefined_constant_refinements.rb +5 -7
- data/lib/rigor/builtins/regex_refinement.rb +21 -13
- data/lib/rigor/builtins/static_return_refinements.rb +7 -6
- data/lib/rigor/cache/annotation_location.rb +2 -4
- data/lib/rigor/cache/descriptor.rb +63 -20
- data/lib/rigor/cache/engine_source.rb +33 -5
- data/lib/rigor/cache/file_digest.rb +9 -1
- data/lib/rigor/cache/incremental_snapshot.rb +72 -6
- data/lib/rigor/cache/rbs_cache_producer.rb +4 -0
- 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 +112 -14
- data/lib/rigor/cache/rbs_environment.rb +8 -4
- data/lib/rigor/cache/rbs_known_class_names.rb +0 -3
- data/lib/rigor/cache/store.rb +76 -32
- data/lib/rigor/ci_detector.rb +1 -0
- 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 +4 -4
- data/lib/rigor/cli/docs_command.rb +6 -6
- 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 +4 -4
- data/lib/rigor/cli/plugins_command.rb +2 -1
- data/lib/rigor/cli/prism_colorizer.rb +1 -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 +212 -31
- data/lib/rigor/cli/skill_command.rb +2 -2
- data/lib/rigor/cli/skill_deep_probe.rb +4 -4
- data/lib/rigor/cli/skill_describe.rb +35 -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 +29 -11
- data/lib/rigor/cli/type_of_renderer.rb +20 -9
- data/lib/rigor/cli/type_of_template_probe.rb +189 -0
- 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 +89 -9
- data/lib/rigor/config_audit.rb +30 -5
- data/lib/rigor/configuration/severity_profile.rb +25 -9
- data/lib/rigor/configuration.rb +109 -7
- data/lib/rigor/effects/ancestry_recorder.rb +191 -0
- data/lib/rigor/effects/attribution.rb +12 -5
- data/lib/rigor/effects/callee_rule.rb +368 -0
- data/lib/rigor/effects/catalog.rb +7 -4
- data/lib/rigor/effects/collector.rb +11 -5
- data/lib/rigor/effects/config_envelopes.rb +15 -10
- data/lib/rigor/effects/definition_context.rb +179 -0
- data/lib/rigor/effects/definition_lines.rb +25 -6
- data/lib/rigor/effects/effect_table.rb +11 -4
- data/lib/rigor/effects/entry_points.rb +0 -2
- data/lib/rigor/effects/envelope_check.rb +9 -9
- data/lib/rigor/effects/envelope_index.rb +20 -8
- data/lib/rigor/effects/file_collection.rb +59 -5
- data/lib/rigor/effects/framework_units.rb +5 -7
- data/lib/rigor/effects/identity.rb +20 -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/local_ownership.rb +38 -12
- data/lib/rigor/effects/method_key.rb +22 -1
- data/lib/rigor/effects/mutation_classifier.rb +23 -12
- data/lib/rigor/effects/plugin_facts.rb +47 -37
- data/lib/rigor/effects/propagator.rb +297 -19
- data/lib/rigor/effects/registry.rb +1 -1
- data/lib/rigor/effects/scanner.rb +122 -73
- data/lib/rigor/effects/signature_sources.rb +4 -6
- data/lib/rigor/effects/snapshot.rb +12 -11
- data/lib/rigor/effects/snapshot_diff.rb +1 -1
- data/lib/rigor/effects/summary.rb +27 -4
- data/lib/rigor/effects/unit_scan.rb +393 -38
- data/lib/rigor/effects/unknown_label_check.rb +3 -8
- data/lib/rigor/effects/unknown_label_report.rb +3 -4
- data/lib/rigor/effects/visibility.rb +101 -0
- 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 +2 -2
- data/lib/rigor/environment/installed_gem_set.rb +85 -0
- data/lib/rigor/environment/lockfile_resolver.rb +68 -4
- data/lib/rigor/environment/member_consistency/comparator.rb +708 -0
- data/lib/rigor/environment/member_consistency.rb +298 -0
- 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 +674 -79
- data/lib/rigor/environment.rb +174 -24
- data/lib/rigor/flow_contribution/merger.rb +0 -2
- data/lib/rigor/flow_contribution.rb +11 -13
- data/lib/rigor/hashing/xxh3.rb +264 -0
- data/lib/rigor/inference/acceptance.rb +292 -17
- data/lib/rigor/inference/block_auto_splat.rb +216 -0
- data/lib/rigor/inference/block_call_timing.rb +338 -0
- data/lib/rigor/inference/block_parameter_binder.rb +75 -30
- data/lib/rigor/inference/block_repetition.rb +71 -0
- data/lib/rigor/inference/body_fixpoint.rb +7 -6
- data/lib/rigor/inference/budget_trace.rb +3 -6
- data/lib/rigor/inference/builtins/method_catalog.rb +2 -1
- data/lib/rigor/inference/builtins/string_catalog.rb +1 -1
- data/lib/rigor/inference/captured_locals.rb +389 -18
- data/lib/rigor/inference/closure_escape_analyzer.rb +159 -17
- data/lib/rigor/inference/content_join.rb +200 -27
- data/lib/rigor/inference/coverage_scanner.rb +4 -6
- data/lib/rigor/inference/def_return_typer.rb +11 -7
- data/lib/rigor/inference/define_method_block_self.rb +64 -0
- data/lib/rigor/inference/dynamic_origin.rb +1 -1
- data/lib/rigor/inference/element_read_widening.rb +180 -0
- data/lib/rigor/inference/error_info.rb +196 -0
- data/lib/rigor/inference/expression_typer.rb +2124 -468
- data/lib/rigor/inference/external_ancestor_resolution.rb +267 -0
- data/lib/rigor/inference/fork_map.rb +5 -7
- data/lib/rigor/inference/fresh_frame_blocks.rb +127 -0
- data/lib/rigor/inference/global_write_census.rb +239 -0
- data/lib/rigor/inference/guard_rebinding.rb +447 -0
- data/lib/rigor/inference/hash_lookup_mutation.rb +88 -0
- data/lib/rigor/inference/hkt_reducer.rb +2 -3
- data/lib/rigor/inference/hkt_registry.rb +4 -7
- data/lib/rigor/inference/index_write_widening.rb +16 -7
- data/lib/rigor/inference/indexed_narrowing.rb +61 -9
- data/lib/rigor/inference/jump_targets.rb +82 -0
- data/lib/rigor/inference/last_line/implicit_self.rb +210 -0
- data/lib/rigor/inference/last_line/self_evidence.rb +329 -0
- data/lib/rigor/inference/last_line.rb +340 -0
- data/lib/rigor/inference/last_status.rb +144 -0
- data/lib/rigor/inference/macro_block_self_type.rb +168 -21
- data/lib/rigor/inference/match_rebinding/calls.rb +281 -0
- data/lib/rigor/inference/match_rebinding/frame.rb +148 -0
- data/lib/rigor/inference/match_rebinding/operands.rb +236 -0
- data/lib/rigor/inference/match_rebinding/self_calls.rb +83 -0
- data/lib/rigor/inference/match_rebinding.rb +392 -0
- data/lib/rigor/inference/method_dispatcher/alias_strict_nominals.rb +36 -0
- data/lib/rigor/inference/method_dispatcher/block_folding.rb +87 -33
- 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/facet_distribution.rb +147 -0
- data/lib/rigor/inference/method_dispatcher/file_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/hash_transform_keys_folding.rb +191 -0
- data/lib/rigor/inference/method_dispatcher/iterator_dispatch.rb +6 -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/match_data_folding.rb +159 -0
- 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 +165 -111
- data/lib/rigor/inference/method_dispatcher/process_folding.rb +56 -0
- data/lib/rigor/inference/method_dispatcher/proven_overload.rb +72 -0
- data/lib/rigor/inference/method_dispatcher/random_folding.rb +82 -0
- data/lib/rigor/inference/method_dispatcher/rbs_dispatch.rb +1046 -69
- 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/self_substitute.rb +142 -0
- data/lib/rigor/inference/method_dispatcher/set_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/shape_dispatch.rb +129 -54
- 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 +5 -6
- 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 +225 -25
- data/lib/rigor/inference/method_parameter_binder.rb +12 -9
- data/lib/rigor/inference/multi_target_binder.rb +341 -55
- data/lib/rigor/inference/mutation_rejoin.rb +171 -0
- data/lib/rigor/inference/mutation_widening.rb +156 -85
- data/lib/rigor/inference/narrowing.rb +835 -162
- data/lib/rigor/inference/operand_effects.rb +167 -0
- data/lib/rigor/inference/operand_walk.rb +88 -0
- data/lib/rigor/inference/optimistic_origin.rb +153 -16
- data/lib/rigor/inference/origin_lookup.rb +2 -3
- data/lib/rigor/inference/parameter_inference_collector.rb +7 -7
- data/lib/rigor/inference/pre_eval_constants.rb +6 -5
- data/lib/rigor/inference/precision_scanner.rb +3 -4
- data/lib/rigor/inference/project_method_ownership.rb +136 -0
- data/lib/rigor/inference/project_patched_methods.rb +9 -4
- data/lib/rigor/inference/project_patched_scanner.rb +10 -6
- 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 +93 -4
- data/lib/rigor/inference/receiver_blind_block.rb +219 -0
- data/lib/rigor/inference/refinement_mutation.rb +76 -0
- data/lib/rigor/inference/repeated_or_writes.rb +463 -0
- data/lib/rigor/inference/return_barrier.rb +54 -0
- data/lib/rigor/inference/rewrite_mutation.rb +120 -0
- data/lib/rigor/inference/scope_indexer.rb +5228 -627
- data/lib/rigor/inference/statement_evaluator.rb +3452 -595
- data/lib/rigor/inference/stored_block_call.rb +54 -0
- data/lib/rigor/inference/string_mutation.rb +97 -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/unknown_store_widening.rb +200 -0
- data/lib/rigor/inference/unthreaded_rebinds.rb +282 -0
- 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 +0 -1
- data/lib/rigor/language_server/diagnostic_publisher.rb +7 -6
- 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 +4 -4
- data/lib/rigor/language_server/incremental_sync.rb +6 -6
- data/lib/rigor/language_server/project_context.rb +7 -8
- 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/mcp/server.rb +2 -1
- data/lib/rigor/plugin/base.rb +258 -26
- data/lib/rigor/plugin/box_probe.rb +91 -0
- data/lib/rigor/plugin/bundled_catalog.rb +167 -0
- data/lib/rigor/plugin/effect_attribution.rb +65 -11
- 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 +33 -13
- data/lib/rigor/plugin/macro/block_as_method.rb +45 -6
- 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 +94 -11
- data/lib/rigor/plugin/registry.rb +76 -12
- data/lib/rigor/plugin/source_rbs_synthesis_reporter.rb +21 -4
- data/lib/rigor/plugin/template_unit.rb +196 -0
- data/lib/rigor/plugin/trust_policy.rb +2 -4
- data/lib/rigor/plugin/type_node_resolver.rb +3 -3
- data/lib/rigor/plugin.rb +1 -0
- 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 +14 -12
- data/lib/rigor/protection/kill_signature.rb +1 -4
- data/lib/rigor/protection/measurement_integrity.rb +1 -3
- data/lib/rigor/protection/mutation_cache.rb +7 -11
- 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 +4 -6
- data/lib/rigor/rbs_extended/reporter.rb +36 -10
- data/lib/rigor/rbs_extended.rb +88 -21
- data/lib/rigor/reflection/constant_ancestors.rb +97 -0
- data/lib/rigor/reflection/constant_path.rb +139 -0
- data/lib/rigor/reflection.rb +93 -110
- data/lib/rigor/runtime/jit.rb +6 -8
- data/lib/rigor/scope/discovery_index.rb +165 -2
- data/lib/rigor/scope.rb +1041 -32
- data/lib/rigor/sig_gen/alias_index.rb +289 -0
- data/lib/rigor/sig_gen/classification.rb +22 -5
- data/lib/rigor/sig_gen/declaration_equivalence.rb +127 -0
- data/lib/rigor/sig_gen/effect_annotation.rb +202 -0
- data/lib/rigor/sig_gen/generator.rb +673 -53
- data/lib/rigor/sig_gen/inline_declarations.rb +184 -0
- 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/method_candidate.rb +47 -3
- data/lib/rigor/sig_gen/observation_collector.rb +18 -16
- 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 +128 -14
- data/lib/rigor/sig_gen/skip_reason_catalog.rb +154 -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/write_result.rb +19 -3
- data/lib/rigor/sig_gen/writer.rb +189 -41
- data/lib/rigor/sig_gen.rb +3 -0
- 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 +0 -6
- data/lib/rigor/source/parameter_envelope.rb +72 -0
- data/lib/rigor/source.rb +1 -0
- 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 +144 -5
- data/lib/rigor/type/data_class.rb +2 -2
- data/lib/rigor/type/data_instance.rb +4 -4
- data/lib/rigor/type/difference.rb +1 -0
- data/lib/rigor/type/float_range.rb +128 -0
- data/lib/rigor/type/hash_shape.rb +6 -6
- data/lib/rigor/type/integer_range.rb +13 -8
- data/lib/rigor/type/nominal.rb +8 -2
- data/lib/rigor/type/refined.rb +4 -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/lib/rigor.rb +1 -0
- 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/effects.rb +1 -0
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable.rb +10 -5
- 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 +14 -4
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/analyzer.rb +32 -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/controller_scan.rb +96 -0
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/effects.rb +65 -8
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/erb_compiler.rb +270 -0
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/render_locals.rb +402 -0
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/view_assigns.rb +370 -0
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/view_units.rb +132 -0
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack.rb +264 -3
- data/plugins/rigor-actionpack/sig/action_controller.rbs +71 -0
- data/plugins/rigor-actionpack/sig/action_view.rbs +43 -0
- data/plugins/rigor-active-model-serializers/lib/rigor/plugin/active_model_serializers/serializer_discoverer.rb +220 -0
- data/plugins/rigor-active-model-serializers/lib/rigor/plugin/active_model_serializers/serializer_index.rb +56 -0
- data/plugins/rigor-active-model-serializers/lib/rigor/plugin/active_model_serializers.rb +263 -0
- data/plugins/rigor-active-model-serializers/lib/rigor-active-model-serializers.rb +7 -0
- data/plugins/rigor-active-model-serializers/sig/active_model_serializers.rbs +45 -0
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/analyzer.rb +0 -4
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/effects.rb +2 -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 +10 -5
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/analyzer.rb +35 -3
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/effects.rb +72 -12
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_discoverer.rb +383 -7
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_index.rb +14 -6
- 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 +322 -41
- data/plugins/rigor-activerecord/sig/active_record/framework.rbs +123 -0
- data/plugins/rigor-activerecord/sig/active_record/relation.rbs +206 -31
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage.rb +26 -14
- data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext/effects.rb +9 -2
- 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 +290 -19
- data/plugins/rigor-devise/lib/rigor/plugin/devise.rb +1 -0
- data/plugins/rigor-dry-monads/lib/rigor/plugin/dry_monads.rb +3 -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 +2 -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/types.rb +1 -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-grape/lib/rigor/plugin/grape.rb +141 -0
- data/plugins/rigor-grape/lib/rigor-grape.rb +6 -0
- data/plugins/rigor-grape/sig/grape.rbs +263 -0
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql/type_scanner.rb +8 -6
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql.rb +78 -5
- data/plugins/rigor-graphql/sig/graphql.rbs +485 -0
- 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 +2 -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 +12 -7
- 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 +36 -37
- 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 +0 -10
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/devise_routes.rb +5 -3
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/doorkeeper_routes.rb +3 -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 +10 -17
- 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/same_line_annotations.rb +149 -0
- data/plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline.rb +324 -18
- 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 +2 -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 +10 -5
- 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 +3 -5
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/type_translator.rb +7 -5
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet.rb +51 -6
- data/plugins/rigor-sorbet/sig/sorbet.rbs +277 -0
- data/plugins/rigor-statesman/lib/rigor/plugin/statesman.rb +1 -0
- data/sig/rigor/analysis/baseline.rbs +69 -7
- data/sig/rigor/analysis/fact_store.rbs +1 -1
- data/sig/rigor/analysis/project_scan.rbs +74 -0
- data/sig/rigor/analysis/reachability/scan_cache.rbs +12 -0
- data/sig/rigor/cache.rbs +2 -3
- data/sig/rigor/effects/config_envelopes.rbs +100 -0
- data/sig/rigor/effects/effect_table.rbs +60 -0
- data/sig/rigor/effects/envelope.rbs +97 -0
- data/sig/rigor/effects/envelope_index.rbs +33 -0
- data/sig/rigor/effects/file_collection.rbs +81 -0
- data/sig/rigor/effects/label.rbs +26 -0
- data/sig/rigor/effects/label_set.rbs +46 -0
- data/sig/rigor/effects/method_key.rbs +24 -0
- data/sig/rigor/effects/origin.rbs +50 -0
- data/sig/rigor/effects/plugin_facts.rbs +141 -0
- data/sig/rigor/effects/registry.rbs +68 -0
- data/sig/rigor/effects/summary.rbs +50 -0
- data/sig/rigor/effects/taint_cause.rbs +12 -0
- data/sig/rigor/environment.rbs +17 -10
- data/sig/rigor/inference/optimistic_origin.rbs +10 -0
- data/sig/rigor/inference.rbs +9 -14
- data/sig/rigor/plugin/additional_initializer.rbs +36 -0
- data/sig/rigor/plugin/base.rbs +30 -7
- data/sig/rigor/plugin/effect_ancestry.rbs +27 -0
- data/sig/rigor/plugin/effect_attribution.rbs +66 -0
- data/sig/rigor/plugin/effect_edge.rbs +33 -0
- data/sig/rigor/plugin/effect_entry_points.rbs +25 -0
- data/sig/rigor/plugin/io_boundary.rbs +4 -0
- data/sig/rigor/plugin/loader.rbs +3 -3
- data/sig/rigor/plugin/manifest.rbs +51 -11
- data/sig/rigor/plugin/protocol_contract.rbs +68 -0
- data/sig/rigor/plugin/registry.rbs +62 -1
- data/sig/rigor/plugin.rbs +1 -1
- data/sig/rigor/rbs_extended.rbs +1 -1
- data/sig/rigor/reflection.rbs +9 -6
- data/sig/rigor/scope.rbs +148 -12
- data/sig/rigor/sig_gen/skip_reason_catalog.rbs +21 -0
- data/sig/rigor/source.rbs +4 -4
- data/sig/rigor/testing.rbs +10 -4
- data/sig/rigor/type.rbs +33 -1
- data/sig/rigor.rbs +39 -20
- data/skills/rigor-ask/SKILL.md +16 -11
- data/skills/rigor-baseline-reduce/SKILL.md +4 -6
- data/skills/rigor-ci-setup/SKILL.md +17 -21
- data/skills/rigor-doctor/SKILL.md +24 -22
- data/skills/rigor-doctor/references/01-checks.md +97 -33
- data/skills/rigor-editor-setup/SKILL.md +6 -4
- data/skills/rigor-mcp-setup/SKILL.md +5 -4
- data/skills/rigor-monkeypatch-resolve/SKILL.md +5 -3
- data/skills/rigor-next-steps/SKILL.md +4 -2
- data/skills/rigor-plugin-author/SKILL.md +19 -23
- data/skills/rigor-plugin-author/references/01-plan-and-scaffold.md +9 -8
- data/skills/rigor-plugin-author/references/02-walker-and-types.md +25 -27
- data/skills/rigor-plugin-author/references/03-test-and-ship.md +6 -8
- data/skills/rigor-plugin-review/SKILL.md +6 -4
- data/skills/rigor-plugin-review/references/01-best-practices-checklist.md +2 -1
- data/skills/rigor-plugin-tune/SKILL.md +4 -2
- data/skills/rigor-project-init/SKILL.md +15 -10
- data/skills/rigor-project-init/references/01-detect.md +13 -9
- data/skills/rigor-project-init/references/02-configure.md +43 -14
- data/skills/rigor-project-init/references/03-baseline-and-bugs.md +14 -14
- data/skills/rigor-project-init/references/04-sig-uplift.md +27 -14
- data/skills/rigor-project-init/references/06-agent-contract.md +67 -0
- data/skills/rigor-protection-uplift/SKILL.md +4 -6
- data/skills/rigor-rbs-setup/SKILL.md +4 -2
- data/skills/rigor-type-oracle/SKILL.md +226 -0
- data/skills/rigor-type-oracle/references/01-oracle-commands.md +265 -0
- data/skills/rigor-type-oracle/references/02-agents-md-fragment.md +52 -0
- data/skills/rigor-type-oracle/references/03-gap-protocol.md +125 -0
- data/skills/rigor-unused-adjudicate/SKILL.md +12 -7
- data/skills/rigor-upgrade/SKILL.md +13 -8
- metadata +133 -3
- data/lib/rigor/cli/probe_environment.rb +0 -85
- data/sig/rigor/inference/builtins/numeric_catalog.rbs +0 -3
|
@@ -292,7 +292,7 @@ class refinement carriers, produced automatically by narrowing.
|
|
|
292
292
|
| --- | --- | --- |
|
|
293
293
|
| `non-empty-string` | a `NonEmptyString` value class wrapping validation | Rigor produces it from `unless s.empty?`, no wrapper type. |
|
|
294
294
|
| `positive-int` | a `PositiveInt` value object, or a runtime guard | Rigor narrows from `n > 0`. |
|
|
295
|
-
| `
|
|
295
|
+
| `Integer[1..9]` | an `enum` of nine constants, or a range check | Rigor's range carrier handles arbitrary bounds without enumerating them. |
|
|
296
296
|
| `numeric-string` | `string` + `int.TryParse` discipline | No type-level analogue in either language. |
|
|
297
297
|
| `non-empty-array[T]` | a non-empty-collection value class | Rigor produces it from `unless arr.empty?`. |
|
|
298
298
|
|
|
@@ -379,7 +379,7 @@ longer than you might expect, because neither has literal types:
|
|
|
379
379
|
`Constant<"FOO">`, not `String`. Rigor catalogues which
|
|
380
380
|
built-in methods are pure and folds through them.
|
|
381
381
|
- **First-class refinements.** `non-empty-string`, `positive-int`,
|
|
382
|
-
`
|
|
382
|
+
`Integer[1..9]`, `numeric-string` — invariants on ordinary types,
|
|
383
383
|
no value-class wrapper.
|
|
384
384
|
- **Structural facets without a declaration.** A Ruby object that
|
|
385
385
|
has the right methods satisfies an RBS `interface` (a
|
|
@@ -71,7 +71,7 @@ features one at a time (`Literal`, `LiteralString`, `TypeIs`,
|
|
|
71
71
|
| `non-empty-string` | (no built-in; PEP 675's `LiteralString` is closest in spirit but different in semantics) |
|
|
72
72
|
| `literal-string` | `LiteralString` (PEP 675) — provably built from source-code literals. **Direct match.** |
|
|
73
73
|
| `positive-int` | (no built-in; convention is `Annotated[int, Gt(0)]` with third-party validators) |
|
|
74
|
-
| `
|
|
74
|
+
| `Integer[min..max]` | (no built-in; same `Annotated[int, Range(...)]` convention) |
|
|
75
75
|
| `numeric-string` | (no built-in) |
|
|
76
76
|
| `non-empty-array[T]` | (no built-in; some libraries use `tuple[T, *tuple[T, ...]]`) |
|
|
77
77
|
| `Constant<42>` | `Literal[42]` |
|
|
@@ -286,7 +286,7 @@ draws the distinction in full.
|
|
|
286
286
|
`Hash`.
|
|
287
287
|
- **First-class refinement carriers with narrowing.**
|
|
288
288
|
`non-empty-string`, `positive-int`, `numeric-string`,
|
|
289
|
-
`
|
|
289
|
+
`Integer[min..max]` — values restricted by predicate, narrowed
|
|
290
290
|
by the corresponding Ruby predicate methods.
|
|
291
291
|
- **No-false-positives stance.** mypy will warn about dynamic
|
|
292
292
|
code unless `--no-warn-unused-ignores` or `--ignore-missing-imports`
|
|
@@ -53,7 +53,7 @@ is the closest match of any peer.
|
|
|
53
53
|
| `numeric-string` | `numeric-string` | Identical. |
|
|
54
54
|
| `lowercase-string` | `lowercase-string` | Identical. |
|
|
55
55
|
| `class-string` | `Singleton[T]` | Equivalent shape. |
|
|
56
|
-
| `int<1, 9>` | `
|
|
56
|
+
| `int<1, 9>` | `Integer[1..9]` | Same carrier; Rigor spells the bound as the Ruby range literal `Range#cover?` reads (`Integer[1..]`, `Integer[..9]`). |
|
|
57
57
|
| `positive-int` | `positive-int` | Identical. |
|
|
58
58
|
| `negative-int` | `negative-int` | Identical. |
|
|
59
59
|
| `non-zero-int` | `non-zero-int` | Identical. |
|
|
@@ -274,7 +274,7 @@ by narrowing.
|
|
|
274
274
|
| --- | --- | --- |
|
|
275
275
|
| `non-empty-string` | `struct NonEmptyString(String)` newtype | Rigor produces it from `unless s.empty?`, no wrapper. |
|
|
276
276
|
| `positive-int` | `struct PositiveInt(u32)` newtype | Rigor narrows from `n > 0`. |
|
|
277
|
-
| `
|
|
277
|
+
| `Integer[1..9]` | newtype + range check, or const generics gymnastics | Rigor's range carrier handles arbitrary bounds directly. |
|
|
278
278
|
| `numeric-string` | newtype wrapping validated parse | No type-level analogue. |
|
|
279
279
|
| `non-empty-array[T]` | newtype over `Vec<T>` | Rigor produces it from `unless arr.empty?`. |
|
|
280
280
|
|
|
@@ -19,7 +19,7 @@ specification](../type-specification/README.md), the spec binds.
|
|
|
19
19
|
| What about types that may or may not match? | Gradual consistency (`~`) | The `Dynamic[T]` carrier and the trinary certainty `yes / no / maybe` |
|
|
20
20
|
| How are user types identified? | Nominal vs structural | **Nominal-first hybrid** — classes by name, plus structural facets (`interface`, `HashShape`, capability roles) |
|
|
21
21
|
| How are generics expressed? | Parametric polymorphism (System F-style, but predicative) | RBS generics `class Array[Elem]`, method generics `def map: [U] () { (Elem) -> U } -> Array[U]` |
|
|
22
|
-
| How is "x is a non-empty string" expressed? | Refinement / predicate subtyping | First-class refinement carriers (`non-empty-string`, `
|
|
22
|
+
| How is "x is a non-empty string" expressed? | Refinement / predicate subtyping | First-class refinement carriers (`non-empty-string`, `Integer[min..max]`, …) |
|
|
23
23
|
| How does `if x.is_a?(String)` change `x`'s type? | Occurrence typing / flow-sensitive narrowing | Edge-aware narrowing with trinary certainty |
|
|
24
24
|
| What about side effects? | Effect systems | The engine's effect model (mutation, exception, escape) — internal, not user-visible |
|
|
25
25
|
| Soundness or completeness? | Pick one (or neither) | **Neither in full** — Rigor optimises for no-false-positives, with a robustness-principle bias |
|
|
@@ -528,7 +528,7 @@ refinements with reserved names:
|
|
|
528
528
|
| `non-empty-string` | `s : String, s.size >= 1` | refinement on `String` |
|
|
529
529
|
| `numeric-string` | `s : String, s =~ /\A[+-]?\d+(\.\d+)?\z/` | refinement on `String` |
|
|
530
530
|
| `literal-string` | "provably built from literals" | refinement on `String` |
|
|
531
|
-
| `
|
|
531
|
+
| `Integer[min..max]` | `n : Integer, min <= n <= max` | range carrier |
|
|
532
532
|
| `non-zero-int` | `n : Integer, n != 0` | refinement on `Integer` |
|
|
533
533
|
| `positive-int` | `n : Integer, n > 0` | refinement on `Integer` |
|
|
534
534
|
| `non-empty-array[T]` | `arr : Array[T], arr.size >= 1` | refinement on `Array[T]` |
|
|
@@ -1491,7 +1491,7 @@ here so you can stop looking:
|
|
|
1491
1491
|
and Rigor does not synthesise it.
|
|
1492
1492
|
- **Full dependent types.** No `Vec[n, T]` with `n : Integer`.
|
|
1493
1493
|
Type-checking is decidable but inference is not; integer-range
|
|
1494
|
-
refinements (`
|
|
1494
|
+
refinements (`Integer[min..max]`) cover the most common practical
|
|
1495
1495
|
need without crossing the line.
|
|
1496
1496
|
- **Row polymorphism as a user-quantifiable axis.** `HashShape`
|
|
1497
1497
|
carries open-vs-closed semantics internally but does not
|
|
@@ -1581,7 +1581,7 @@ they map to the sections of this appendix:
|
|
|
1581
1581
|
matching and exhaustiveness."
|
|
1582
1582
|
- Rondon, Kawaguchi & Jhala. "Liquid Types." *PLDI 2008.* The
|
|
1583
1583
|
refinement-types-with-SMT framework that informs the
|
|
1584
|
-
`
|
|
1584
|
+
`Integer[min..max]` carrier (Rigor uses a much weaker, decidable
|
|
1585
1585
|
fragment).
|
|
1586
1586
|
- Lucassen & Gifford. "Polymorphic Effect Systems."
|
|
1587
1587
|
*POPL 1988.* Origin of effect systems.
|
|
@@ -101,7 +101,7 @@ positive, an array that is provably non-empty.
|
|
|
101
101
|
| --- | --- | --- |
|
|
102
102
|
| `non-empty-string` | `\`${string}${string}\`` (template literal trick) or branded `NonEmptyString` | Awkward in TS; Rigor produces it from `unless s.empty?` automatically. |
|
|
103
103
|
| `positive-int` | branded `PositiveInt` | TS users tend to skip the brand — Rigor narrows from `n > 0`. |
|
|
104
|
-
| `
|
|
104
|
+
| `Integer[1..9]` | union of literal types `1 \| 2 \| 3 \| ... \| 9` | Rigor's range carrier handles arbitrary bounds without exploding. |
|
|
105
105
|
| `numeric-string` | (none useful) | TS has no equivalent; Rigor narrows from regex matches against numeric patterns. |
|
|
106
106
|
| `non-empty-array[T]` | `[T, ...T[]]` (tuple-with-rest) | TS has the encoding but few APIs use it; Rigor produces it from `unless arr.empty?`. |
|
|
107
107
|
|
data/docs/llms.txt
CHANGED
|
@@ -42,6 +42,8 @@ Skill with `rigor skill <name>`. (The canonical web copy is
|
|
|
42
42
|
- `15-type-protection-coverage` — `rigor coverage --protection`.
|
|
43
43
|
- `16-rbs-extended-annotations` — the `%a{rigor:v1:…}` annotations.
|
|
44
44
|
- `17-driving-improvement` — the `rigor-next-steps`-driven improvement loop.
|
|
45
|
+
- `18-removing-dead-code` — working `rigor unused` as a campaign on an old codebase.
|
|
46
|
+
- `19-effect-labels` — `rigor effects`, the `.rigor-effects.yml` snapshot, and `%a{pure}`.
|
|
45
47
|
|
|
46
48
|
## Handbook (read with `rigor docs <name>`)
|
|
47
49
|
|
|
@@ -45,6 +45,7 @@ the `paths:` list from the configuration file.
|
|
|
45
45
|
| `--baseline=PATH` | Load a baseline file, overriding config. |
|
|
46
46
|
| `--no-baseline` | Ignore any configured baseline. |
|
|
47
47
|
| `--baseline-strict` | Fail the run on any baseline drift — a CI gate. |
|
|
48
|
+
| `--fail-on=SEVERITY` | Exit non-zero when a diagnostic at or above `SEVERITY` (`error`, the default; `warning`; or `info`) survives baseline filtering — raises the exit-status bar above the default `:error`-only reading for CI gates that want it, without changing `--format json`'s `success` / `error_count` fields. |
|
|
48
49
|
| `--treat-all-as-inline-rbs` | Force-load `rigor-rbs-inline` with `require_magic_comment: false`, so every analysed file is treated as inline-RBS without the `# rbs_inline: enabled` comment (ADR-32). |
|
|
49
50
|
| `--bleeding-edge[=ids]` | Adopt the bleeding-edge overlay for this run, overriding the configured [`bleeding_edge:`](03-configuration.md) selection (ADR-50 § WD2). Bare adopts every queued feature; `--bleeding-edge=a,b` adopts only the named feature ids. Inspect it with [`rigor show-bleedingedge`](#rigor-show-bleedingedge). |
|
|
50
51
|
| `--no-bleeding-edge` | Ignore any configured `bleeding_edge:` selection for this run (adopt none). |
|
|
@@ -52,7 +53,9 @@ the `paths:` list from the configuration file.
|
|
|
52
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). |
|
|
53
54
|
|
|
54
55
|
Exit `0` when no error-severity diagnostics remain, `1` when
|
|
55
|
-
any are reported, `64` on a usage error.
|
|
56
|
+
any are reported, `64` on a usage error. `--fail-on` raises that
|
|
57
|
+
bar to `warning` or `info` for callers (CI gates, `make check`)
|
|
58
|
+
that want the stricter reading.
|
|
56
59
|
|
|
57
60
|
### Editor mode scope
|
|
58
61
|
|
|
@@ -135,6 +138,39 @@ truncation explicit. `--trace` records fail-soft fallbacks,
|
|
|
135
138
|
after the rows of a line table in text output. The editor-mode
|
|
136
139
|
`--tmp-file` / `--instead-of` pair is accepted as on `check`.
|
|
137
140
|
|
|
141
|
+
A template a plugin compiles into Ruby (an ERB view under
|
|
142
|
+
`rigor-actionpack`) is probed the way `rigor check` analyses
|
|
143
|
+
it: the compiled Ruby is typed under the view's declared
|
|
144
|
+
`self`, locals and instance variables, and `LINE:COL` are the
|
|
145
|
+
template's own. A column answers only when it lies in Ruby the
|
|
146
|
+
compiler copied verbatim — the `@user.name` in
|
|
147
|
+
`<%= @user.name %>` — and denotes exactly one compiled
|
|
148
|
+
expression. A column in HTML text, in code the plugin rewrote
|
|
149
|
+
(a layout's `<%= yield %>`), or in bytes copied to more than
|
|
150
|
+
one place prints `no expression found at …` with the reason
|
|
151
|
+
and exits `1`; the command never answers about a nearby
|
|
152
|
+
node instead. Two tags that name the same thing (`<%= v %>`
|
|
153
|
+
beside `<% if "a" <= v %>`, or `<%= v %> <%= v.to_s %>`)
|
|
154
|
+
decline for that reason as well; a name repeated inside ONE
|
|
155
|
+
tag still answers. A bare `FILE:LINE` lists only the expressions
|
|
156
|
+
that map back to a template column. `--trace` fallbacks are
|
|
157
|
+
reported at the template line, and a JSON fallback carries a
|
|
158
|
+
`column` only when its position maps back to one. A template
|
|
159
|
+
the plugin declined to compile prints
|
|
160
|
+
`plugin declined the template; probing its bytes as Ruby`
|
|
161
|
+
and is probed as plain Ruby, parse error included.
|
|
162
|
+
|
|
163
|
+
The four probe commands — `type-of`, `type-scan`, `trace` and
|
|
164
|
+
`annotate` — build their environment fresh on every invocation
|
|
165
|
+
and never read or write the persistent cache. That is why none
|
|
166
|
+
of them takes `--no-cache`: the flag would have nothing to skip.
|
|
167
|
+
A probe therefore types against the environment `rigor check
|
|
168
|
+
--no-cache` analyses with. The environment a cached (default)
|
|
169
|
+
`rigor check` builds is meant to be identical, and Rigor gates
|
|
170
|
+
the two builds against each other — but if you are chasing a
|
|
171
|
+
disagreement between a probe and a `check` run, comparing
|
|
172
|
+
against `rigor check --no-cache` removes that variable.
|
|
173
|
+
|
|
138
174
|
## `rigor trace`
|
|
139
175
|
|
|
140
176
|
Replay HOW the engine typed a file, step by step, as a
|
|
@@ -429,6 +465,12 @@ rigor explain [rule]
|
|
|
429
465
|
or a family wildcard (`call`, `flow`, `def`, `assert`, `dump`).
|
|
430
466
|
`--format=json` is available. Exit `64` for an unknown rule.
|
|
431
467
|
|
|
468
|
+
It also answers the `sig.skipped.*` identifiers `rigor sig-gen`
|
|
469
|
+
prints when it declines to write a signature — `rigor explain
|
|
470
|
+
sig.skipped.untyped-return` says what the skip means and what to do
|
|
471
|
+
instead. Those are not diagnostic rules, so they are rendered without
|
|
472
|
+
a severity or a suppression line.
|
|
473
|
+
|
|
432
474
|
## `rigor diff`
|
|
433
475
|
|
|
434
476
|
Compare the current diagnostics against a saved baseline JSON
|
|
@@ -457,13 +499,52 @@ rigor sig-gen [paths]
|
|
|
457
499
|
| `--print` | Write RBS to stdout. Default. |
|
|
458
500
|
| `--diff` | Write a unified diff against existing RBS. |
|
|
459
501
|
| `--write` | Write RBS to `sig/<path>.rbs` files. |
|
|
460
|
-
| `--
|
|
502
|
+
| `--check` | Write nothing; print what `--write` with the same options would change, and exit `1` if anything would. The CI freshness gate. |
|
|
503
|
+
| `--overwrite` | Allow tighter-return updates, and inline declarations that disagree with `sig/`, to replace user-authored RBS. |
|
|
461
504
|
| `--include-private` | Emit private and protected methods too. |
|
|
462
505
|
| `--params=untyped\|observed\|observed-strict` | Parameter-typing policy. Default `untyped`. |
|
|
463
|
-
| `--observe=PATH` | Scan `PATH` for call-site observations. Repeatable. |
|
|
506
|
+
| `--observe=PATH` | Scan `PATH` for call-site observations. Repeatable. Default: the configured `test_paths:` (unset: whichever of `spec/` and `test/` exist). |
|
|
464
507
|
| `--new-files` / `--new-methods` / `--tighter-returns` | Emit only that classification. |
|
|
508
|
+
| `--effect-envelopes` | Also emit `%a{rigor:v1:effect …}` for effectful methods. Needs the `effects:` opt-in. |
|
|
509
|
+
| `--no-cache` | Do not read or write the analysis cache. Only effect collection uses it. |
|
|
465
510
|
| `--format=text\|json` | Output format. |
|
|
466
511
|
|
|
512
|
+
`--print`, `--diff`, `--write` and `--check` are mutually exclusive.
|
|
513
|
+
`--check` fails exactly when `--write` would create, change or
|
|
514
|
+
refuse a file, so a tighter return `--write` declines without
|
|
515
|
+
`--overwrite` does not fail it; `--check --overwrite` counts one.
|
|
516
|
+
See [handbook chapter 11](../handbook/11-sig-gen.md#keeping-sig-current-in-ci).
|
|
517
|
+
|
|
518
|
+
A method declared inline with `# @rbs` / `#:` is written as that
|
|
519
|
+
declaration, not as what its body infers; a parameter-only
|
|
520
|
+
annotation keeps its parameters and takes the return from the body,
|
|
521
|
+
and `initialize` is always `-> void`. When `sig/` already declares
|
|
522
|
+
the method (a `def` or an `attr_*`) and the two disagree as types —
|
|
523
|
+
parameter names and union spelling do not count, overload order
|
|
524
|
+
does — sig-gen changes neither: the method is refused
|
|
525
|
+
(`sig.skipped.inline-differs`, listed under `refused` in `--format=json`),
|
|
526
|
+
and `--write` / `--check` exit `1` until you make them agree or pass
|
|
527
|
+
`--overwrite`, which replaces the whole `sig/` member with the inline
|
|
528
|
+
declaration. For a parameter-only annotation only the parameters are
|
|
529
|
+
compared; the return follows the ordinary proposal rules. A class
|
|
530
|
+
made generic inline is not written unless `sig/` declares it with the
|
|
531
|
+
same type parameters. A project whose Steep reads the same
|
|
532
|
+
annotations sets `sig_gen.inline_declared: skip` in `.rigor.yml` to
|
|
533
|
+
keep those methods out of `sig/`. See
|
|
534
|
+
[handbook chapter 11](../handbook/11-sig-gen.md#methods-declared-inline).
|
|
535
|
+
|
|
536
|
+
When `.rigor.yml` carries an `effects:` block, sig-gen also writes
|
|
537
|
+
`%a{pure}` above a method whose effect summary is **exhaustive**
|
|
538
|
+
(every call it reaches was resolved), **undischarged** (nothing in
|
|
539
|
+
its footprint is only invisible because `effects.tolerated:` says
|
|
540
|
+
so), **claimed** (every callee is described by a catalogue row, a
|
|
541
|
+
plugin, an envelope or a project definition), carries no authored
|
|
542
|
+
bound of its own, and is free of surviving labels in the `≤` lane. Nothing else is annotated, and
|
|
543
|
+
`--effect-envelopes` adds Rigor's own labelled spelling for methods
|
|
544
|
+
that do have a footprint. With no `effects:` block the output is
|
|
545
|
+
byte-for-byte what it was before. See
|
|
546
|
+
[handbook chapter 11](../handbook/11-sig-gen.md#emitting-effect-annotations).
|
|
547
|
+
|
|
467
548
|
Every signature is parsed before it is emitted. A method whose
|
|
468
549
|
generated RBS does not parse is **skipped** (`sig.skipped.unrenderable-rbs`)
|
|
469
550
|
and reported on stderr rather than written — an unparseable
|
|
@@ -481,6 +562,8 @@ not overwrite) is never a silent absence: under `--format=json`
|
|
|
481
562
|
it is a `skipped` row of the `candidates` array with its
|
|
482
563
|
`sig.skipped.*` identifier in `skip_reason`, and in text mode a
|
|
483
564
|
one-line stderr summary counts the skipped methods per reason.
|
|
565
|
+
`rigor explain sig.skipped.untyped-return` (or any of the other skip
|
|
566
|
+
identifiers) explains what the reason means and what to do about it.
|
|
484
567
|
|
|
485
568
|
## `rigor lsp`
|
|
486
569
|
|
|
@@ -577,6 +660,12 @@ see. That is why this is a separate command and never a `rigor check`
|
|
|
577
660
|
diagnostic — see
|
|
578
661
|
[ADR-102](../adr/102-unused-code-reachability-report.md).
|
|
579
662
|
|
|
663
|
+
`rigor unused` refuses `--incremental` and exits non-zero rather
|
|
664
|
+
than quietly running a full pass. Reachability is only sound over a
|
|
665
|
+
whole-project run: with files served from the incremental cache a
|
|
666
|
+
constant would be reported as unused merely because the file that
|
|
667
|
+
references it was not re-scanned. Re-run without the flag.
|
|
668
|
+
|
|
580
669
|
Reachability is computed from **roots**, not by counting references,
|
|
581
670
|
so a cluster of classes that only reference each other is still
|
|
582
671
|
reported. Roots are the declarations in files matching
|
|
@@ -1112,7 +1201,7 @@ operational knobs read the environment instead.
|
|
|
1112
1201
|
| `RIGOR_RACTOR_WORKERS=N` | Worker count for parallel analysis. Sits between the CLI flag and the config key in precedence: `--workers=N` > `RIGOR_RACTOR_WORKERS` > `parallel.workers:` > `0` (sequential). |
|
|
1113
1202
|
| `RIGOR_POOL_BACKEND=ractor` | Opt back into the (off-by-default) Ractor worker pool instead of the active fork-based pool ([ADR-15](../adr/15-ractor-concurrency.md)). Only relevant with a non-zero worker count; the fork pool is the supported backend. |
|
|
1114
1203
|
| `RIGOR_LSP_POOL_MIN_BATCH=N` | Fewest buffers an [`rigor lsp`](#rigor-lsp) batch must carry before analysis is dispatched across the worker pool rather than run in-process (default `16`). Lower it if your project's per-file analysis is expensive enough that pooling pays off sooner. |
|
|
1115
|
-
| `RIGOR_PLUGIN_ISOLATION=none\|process\|ruby_box` | How a plugin's direct calls into its target library are isolated. Default `process`. See [Using plugins § Isolation strategy](07-plugins.md). `RIGOR_BOX` is a legacy alias for `ruby_box`. |
|
|
1204
|
+
| `RIGOR_PLUGIN_ISOLATION=none\|process\|ruby_box` | How a plugin's direct calls into its target library are isolated. Overrides the `plugins_isolation:` configuration key. Default `process`. See [Using plugins § Isolation strategy](07-plugins.md). `RIGOR_BOX` is a legacy alias for `ruby_box`. |
|
|
1116
1205
|
| `RIGOR_STRICT_VALIDATION=1` | Force full-content cache validation for one run (the same as `cache.validation: digest`, and winning over it) — re-hash every file's content instead of trusting its stat metadata. Use it if a filesystem's timestamps or inode numbers cannot be trusted. See [Caching § How a file is checked for changes](12-caching.md#how-a-file-is-checked-for-changes). |
|
|
1117
1206
|
| `RIGOR_DISABLE_YJIT=1` | Opt out of Rigor's deferred YJIT enablement. Rigor turns YJIT on partway through any long run so short runs never pay the JIT warm-up; this variable leaves it off entirely. Diagnostics and allocations are identical either way — the effect is wall-time only. |
|
|
1118
1207
|
| `RIGOR_YJIT_DEADLINE=<seconds>` | Advanced: tune how long a run must last before deferred YJIT enables (default `5.0`). Lower it if your runs are long and you want the JIT sooner; raise it to protect short runs. Ignored when `RIGOR_DISABLE_YJIT=1` is set or YJIT is unavailable. |
|
|
@@ -1126,8 +1215,8 @@ diagnostics about Rigor's own inference cutoffs and memory — see
|
|
|
1126
1215
|
|
|
1127
1216
|
| Code | Meaning |
|
|
1128
1217
|
| --- | --- |
|
|
1129
|
-
| `0` | Success — no error-
|
|
1130
|
-
| `1` | Diagnostics found, or a per-command failure (parse error, missing file, new diagnostics on `diff`, effect drift on `effects check`). |
|
|
1218
|
+
| `0` | Success — no diagnostic at or above the exit threshold (`error` by default; `rigor check --fail-on=SEVERITY` lowers it to `warning` or `info`). |
|
|
1219
|
+
| `1` | Diagnostics found at or above the threshold, or a per-command failure (parse error, missing file, new diagnostics on `diff`, effect drift on `effects check`). |
|
|
1131
1220
|
| `64` | Usage error — unknown command, bad flag, malformed argument, or a value in `.rigor.yml` the loader cannot proceed on. |
|
|
1132
1221
|
|
|
1133
1222
|
`rigor triage` is the exception: it is advisory and always
|
|
@@ -60,6 +60,7 @@ cache:
|
|
|
60
60
|
| `target_ruby` | String | `"4.0"` | The Ruby version *your* project runs — `"X.Y"`, `"X.Y.Z"`, or `"latest"`. Independent of the Ruby Rigor itself runs on. |
|
|
61
61
|
| `paths` | Array | `["lib"]` | Directories or files to analyse. |
|
|
62
62
|
| `exclude` | Array | `[]` | Glob patterns to skip. `vendor/bundle`, `.bundle`, and `node_modules` are always excluded. |
|
|
63
|
+
| `test_paths` | Array | `nil` | The project's test roots: the directories (or files) holding its tests. Relative entries resolve against the config file's directory. Unset auto-detects whichever of `spec/` and `test/` exist; `[]` declares none. `rigor sig-gen --params=observed` reads call sites there to type parameters, and names on stderr a declared root that does not exist. Test roots are not analysed unless `paths:` also lists them, and changing them invalidates no cache. |
|
|
63
64
|
| `includes` | Array | `[]` | Other config files to layer underneath this one. |
|
|
64
65
|
| `fold_platform_specific_paths` | Boolean | `false` | Resolve Ruby-version-conditional load paths when discovering sources. |
|
|
65
66
|
| `parameter_inference` | Boolean | `false` | Opt-in call-site parameter type inference on the `check` walk ([ADR-67](../adr/67-parameter-type-inference.md) WD6). When `true`, an undeclared `def` / `initialize` / setter parameter is typed to the union of its resolved call-site argument types, sharpening downstream ivar reads, folds, and protection coverage. Precision-additive only — the negative rules never fire against an inferred parameter. Cannot be combined with `--incremental`. |
|
|
@@ -73,6 +74,12 @@ cache:
|
|
|
73
74
|
| `pre_eval` | Array | `[]` | Files (or globs) walked before per-file analysis, to register project monkey-patches and publish their top-level constants project-wide. |
|
|
74
75
|
| `plugins` | Array | `[]` | Plugins to activate — see [Using plugins](07-plugins.md). |
|
|
75
76
|
|
|
77
|
+
### Signature generation
|
|
78
|
+
|
|
79
|
+
| Key | Type | Default | Meaning |
|
|
80
|
+
| --- | --- | --- | --- |
|
|
81
|
+
| `sig_gen.inline_declared` | String | `"write"` | What `rigor sig-gen` does with a method already declared inline by `# @rbs` / `#:`. `write` copies the inline declaration into `sig/`, so the generated signature is the complete contract a gem ships, and refuses (exit 1) a `sig/` declaration that later disagrees with the inline one until the two agree or `--overwrite` replaces it. `skip` leaves every method the inline reader declares out of `sig/` (`sig.skipped.inline-declared`): set it when Steep reads the same annotations (`inline: true` beside `signature "sig"`), where a copy would declare each method twice (`DuplicatedMethodDefinition`). The cost of `skip`: a consumer reading only your shipped `sig/` never sees those methods, and an annotation on one — a Rigor refinement included — takes effect only where the source itself is analysed. Any other value, or any other key under `sig_gen:`, is a load error. Only `rigor sig-gen` reads this key, and changing it invalidates no cache. See [handbook chapter 11](../handbook/11-sig-gen.md#methods-declared-inline). |
|
|
82
|
+
|
|
76
83
|
### Config validation warnings
|
|
77
84
|
|
|
78
85
|
`rigor check` warns on STDERR when a configured value silently resolves to
|
|
@@ -93,6 +100,16 @@ rigor: severity_overrides: "flow.bogus" is not a recognized rule id; the overrid
|
|
|
93
100
|
rigor: bundler.lockfile: "./missing/Gemfile.lock" does not exist
|
|
94
101
|
```
|
|
95
102
|
|
|
103
|
+
One warning covers the mirror-image mistake — a path that loads, but only
|
|
104
|
+
half of what you wanted. A bundled plugin ships its RBS *and* a manifest
|
|
105
|
+
recording which of those classes it declares only partially; `plugins:`
|
|
106
|
+
loads both, while pointing `signature_paths:` at the plugin's `sig/` loads
|
|
107
|
+
only the RBS, so calls your own code defines get reported as undefined:
|
|
108
|
+
|
|
109
|
+
```
|
|
110
|
+
rigor: signature_paths: "…/plugins/rigor-activerecord/sig" loads the signatures of the bundled plugin "rigor-activerecord", which `plugins:` does not name — … Add "rigor-activerecord" to `plugins:` instead of naming its `sig/` in `signature_paths:`.
|
|
111
|
+
```
|
|
112
|
+
|
|
96
113
|
The unrecognised-key check covers **top-level** keys, and skips
|
|
97
114
|
the namespaces reserved for other implementations (see below).
|
|
98
115
|
A typo *inside* a group — `cache: { pth: … }` — is caught by
|
|
@@ -170,6 +187,7 @@ explicitly with `bundler.bundle_path:`, or supply signatures another way:
|
|
|
170
187
|
| `cache.max_bytes` | Integer or `null` | `268435456` (256 MB) | LRU eviction cap for the cache directory; `null` disables eviction. See [Caching § Size and eviction](12-caching.md#size-and-eviction). |
|
|
171
188
|
| `cache.validation` | String | `"auto"` | How the cache checks whether a file is unchanged: `auto` behaves as `digest` when a CI environment is detected and as `stat` otherwise; `stat` compares size + nanosecond timestamps + inode and only re-hashes a file whose stat moved; `digest` re-hashes every file's content every run. Both keep the content hash as the sole change authority — `stat` just skips the hash when the stat proves a file untouched. See [Caching § How a file is checked for changes](12-caching.md#how-a-file-is-checked-for-changes). The `RIGOR_STRICT_VALIDATION=1` environment variable forces `digest` for one run and wins over this key; `RIGOR_CI_DETECT=0` disables the CI detection. |
|
|
172
189
|
| `parallel.workers` | Integer | `0` | Parallel worker processes for per-file analysis (fork-based pool today; ADR-15); `0` is sequential. CLI `--workers` and `RIGOR_RACTOR_WORKERS` take precedence. Applies to `--incremental` re-checks as well as full runs. |
|
|
190
|
+
| `plugins_isolation` | String | `null` | How a plugin's call into its target library is isolated — `process` (default) or `none`. `RIGOR_PLUGIN_ISOLATION` overrides it for one invocation; `ruby_box` is that variable only. See [Using plugins](07-plugins.md). |
|
|
173
191
|
| `plugins_io.network` | String | `"disabled"` | Plugin network policy — `disabled` or `allowlist`. |
|
|
174
192
|
| `plugins_io.allowed_paths` | Array | `[]` | Filesystem paths plugins may read. |
|
|
175
193
|
| `plugins_io.allowed_url_hosts` | Array | `[]` | URL hosts plugins may fetch from when `network: allowlist`. |
|
|
@@ -16,6 +16,7 @@ Every rule has a two-segment `family.rule` identifier:
|
|
|
16
16
|
| `call` | Call sites — undefined methods, arity, argument types, nil receivers. |
|
|
17
17
|
| `flow` | Control-flow proofs — always-raises, dead branches, constant conditions. |
|
|
18
18
|
| `def` | Method definitions — return types, ivar writes, visibility. |
|
|
19
|
+
| `global` | Writes to special globals — a value the setter rejects, a read-only variable. |
|
|
19
20
|
| `assert` | `assert_type` checks. |
|
|
20
21
|
| `dump` | `dump_type` notices. |
|
|
21
22
|
|
|
@@ -70,11 +71,14 @@ carries no `documentation_url`.
|
|
|
70
71
|
| <a id="rule-def-override-visibility-reduced"></a>`def.override-visibility-reduced` | An override reduces the visibility it inherits from a project-defined ancestor. | high |
|
|
71
72
|
| <a id="rule-def-override-return-widened"></a>`def.override-return-widened` | An override's declared return type widens the inherited return (covariance). | high |
|
|
72
73
|
| <a id="rule-def-override-param-narrowed"></a>`def.override-param-narrowed` | An override narrows an inherited parameter type (contravariance). | high |
|
|
74
|
+
| <a id="rule-global-write-type-mismatch"></a>`global.write-type-mismatch` | A special global is assigned a literal its setter rejects, so the write raises `TypeError` every time it runs. `$/`, `$-0`, `$,` and `$\` take only a String or nil (`$/ = 1` and `$/ = /x/` report). `$;` and `$-F` take a String, a Regexp, nil, or an object with `to_str`. `$~` takes a MatchData or nil. `$0` and `$PROGRAM_NAME` take a String or an object with `to_str`, so `$0 = nil` and `$0 = :name` report. `$.` takes an Integer, a Float, or an object with `to_int`, so `$. = "3"` reports and `$. = 3r` does not. `$-i` takes a String, nil, false, or an object with `to_str`. `$stdout`, `$>` and `$stderr` take anything that responds to `write`: `$stdout = 1` reports, `$stdout = StringIO.new` does not. Ruby's setter decides, not the global's RBS type. Only a value written as a literal is judged — a number, a string, a symbol, an array, a hash or a regexp literal (interpolated or not), or `nil`, `true` or `false` — so a variable, a method call or a constant never reports, whatever its type. A literal stays silent when your program defines the method the setter asks for (`write`, `to_str`, `to_int`) or a `method_missing` / `respond_to_missing?` / `respond_to?` anywhere, in any spelling and on any class — Rigor cannot always tell which objects such a definition reaches, so it does not try — or when a top-level `include` / `extend` or an ancestor's `include` names a module Rigor has no RBS for. For `$stdout`, `$>` and `$stderr` it also stays silent where a `using` is in effect for a refinement that may add `write`. `$/`, `$-0`, `$,`, `$\` and `$~` accept only their classes, so none of that silences them. A write to `$stdin` is never checked, and a special any file aliases (`alias $stdout $out`, including a `pre_eval:` file) is exempt. `warning` under `lenient`. | high |
|
|
75
|
+
| <a id="rule-global-readonly-write"></a>`global.readonly-write` | A read-only special global is written — `$!`, `$$`, `$?`, `$<`, `$FILENAME`, `$*`, `$:` / `$LOAD_PATH` / `$-I`, `$"` / `$LOADED_FEATURES`, `$-W`, `$-p`, `$-l` or `$-a` — which raises `NameError` whatever the value. Covers `$g = value`, `$g += value` and a multiple-assignment target. `$LOAD_PATH ||= []` never writes and `$LOAD_PATH << dir` is a method call, so neither fires. A special any file aliases (`alias $! $err`) is exempt. An error in every profile. | high |
|
|
73
76
|
| <a id="rule-static-value-use-void"></a>`static.value-use.void` | A value recovered from an author-declared `-> void` return is used in value context (an assignment right-hand side, a call receiver, or a call argument). Off by default; reaches a run only through the `use-of-void-value` bleeding-edge feature (ADR-100). A bare-statement `void` call and a legitimate `top` value both stay silent. | high |
|
|
74
77
|
| <a id="rule-effect-envelope-exceeded"></a>`effect.envelope-exceeded` | A method performs an effect its declared envelope does not admit — its proven effect labels (its own body plus everything it calls) are not covered by the `%a{pure}` or `%a{rigor:v1:effect …}` bound written on it or on its class. Opt-in twice over: it needs an `effects:` block in `.rigor.yml` and an envelope you wrote. Positioned at the Ruby `def`. Unproven ("and possibly more") effects never fire, and `mutate.local` is tolerated by every envelope. | high |
|
|
75
78
|
| <a id="rule-effect-liskov-widened"></a>`effect.liskov-widened` | An override escapes the envelope written on the method it overrides. A `PgRepo` is usable wherever a `Repo` is, so a `%a{rigor:v1:effect io.db}` on `Repo#find` binds `PgRepo#find` too: an implementation may be purer than the bound it inherits, never less pure. Either what the override *does* exceeds the inherited bound, or the envelope the override *declares for itself* is wider than it. Both sides must be authored — nothing fires unless someone wrote an envelope on the ancestor — and only subclassing counts, not `include`. Positioned at the override's `def`. Needs an `effects:` block. | high |
|
|
76
79
|
| <a id="rule-effect-unknown-label"></a>`effect.unknown-label` | An effect declaration names a label the registry does not know — a typo in an envelope (`%a{rigor:v1:effect io.bd}`), or a member of `effects.tolerated:`. The whole tag then reads as unbounded, so the declaration quietly stops doing anything; this says so. Positioned at the declaration: the `.rbs` line, the `.rb` line for an rbs-inline annotation, or `.rigor.yml` for a config value. `# rigor:disable` comments are not read out of `.rbs` or `.rigor.yml`, so use `disable:` or the baseline there. Only fires where the spelling is evidently meant to be a label (close to a known one, next to a known one, dotted, or retired) — a word nothing resembles stays silent, because you may be opening your own vocabulary. Needs an `effects:` block. | high |
|
|
77
80
|
| <a id="rule-effect-annotations-unchecked"></a>`effect.annotations-unchecked` | Your signatures carry `%a{pure}` / `%a{rigor:v1:effect …}` but `.rigor.yml` has no `effects:` block, so nothing checks them. One `:info` per run, positioned at the first annotation. An annotation never turns effect collection on by itself — that would make one line in one file more expensive for every run — so this is how it tells you instead. Add `effects: {}` to opt in, or `disable:` it to keep the annotations documentary. Reads both annotation lanes — `sig/*.rbs` and rbs-inline comments — on every run, a warm `--incremental` with nothing changed included. | — |
|
|
81
|
+
| <a id="rule-rbs-contradicting-signature"></a>`rbs.contradicting-signature` | A method is declared both in your `sig/` and by an inline `# @rbs` / `#:` annotation, and the two provably contradict — no value or call satisfies both: in the return or a parameter every call must pass, the two types share no value (`::String` against `::Integer`). Only absolutely written Ruby core or stdlib classes count: a module such as `Comparable`, a class your project declares, a gem's class, or a relative name like plain `String` never does, or two keyword-free declarations accept positional counts that cannot meet, or one requires a keyword the other cannot take in any form. Overloads are paired by correspondence, not order. Also fires when a member-level `%a{rigor:v1:return: …}` / `%a{rigor:v1:param: …}` refinement shares no value with the type its own member declares. Positioned at the `.rbs` member; Rigor reads that declaration. A stale generated signature is the usual cause: regenerate it, or fix the annotation. Two declarations where one refines the other merge to the more precise one without a word, and a pair Rigor cannot rank drops the inline side with a `source-rbs-annotation-not-honoured` `:info` instead ([Precedence](plugins/rigor-rbs-inline.md#precedence)). An error in every profile. | high |
|
|
78
82
|
| <a id="rule-suppression-unknown-rule"></a>`suppression.unknown-rule` | A `# rigor:disable[-file]` comment names a rule that does not exist (typically a typo), so the suppression silently does nothing. `plugin.`-prefixed tokens are never flagged. | high |
|
|
79
83
|
| <a id="rule-suppression-empty"></a>`suppression.empty` | A `# rigor:disable[-file]` comment lists no rules, so it suppresses nothing. | high |
|
|
80
84
|
| <a id="rule-suppression-unknown-marker"></a>`suppression.unknown-marker` | A comment uses a suppression marker Rigor does not recognise — typically the RuboCop reflex `# rigor:disable-next-line <rule>` or `# rigor:enable <rule>`. Rigor's only markers are `# rigor:disable <rules>` (suppresses on its own line) and `# rigor:disable-file <rules>`, so the comment suppresses nothing. | high |
|
|
@@ -85,6 +89,17 @@ carries no `documentation_url`.
|
|
|
85
89
|
Plugins may contribute further families and rules; `rigor
|
|
86
90
|
explain` lists whatever the active configuration loads.
|
|
87
91
|
|
|
92
|
+
`flow.unreachable-branch` and `flow.always-truthy-condition` fold
|
|
93
|
+
version guards — `RUBY_VERSION` / `RUBY_ENGINE` comparisons, and
|
|
94
|
+
`X::VERSION` for a default gem of the running Ruby — against the
|
|
95
|
+
Ruby interpreter running `rigor`, never `target_ruby`. The
|
|
96
|
+
diagnostic set is therefore host-dependent: the same file can fold
|
|
97
|
+
a different arm on Ruby 3.3 than on Ruby 4.0, and a project whose
|
|
98
|
+
CI pins a different Ruby than your workstation should expect the CI
|
|
99
|
+
run's result, not yours. See
|
|
100
|
+
[Version-guard condition folding](../type-specification/control-flow-analysis.md#version-guard-condition-folding)
|
|
101
|
+
for the exact foldable set.
|
|
102
|
+
|
|
88
103
|
## Evidence tier
|
|
89
104
|
|
|
90
105
|
Every rule in the catalogue above carries an **evidence tier** —
|
data/docs/manual/07-plugins.md
CHANGED
|
@@ -74,23 +74,33 @@ A plugin may want to read a file (a schema dump) or reach the
|
|
|
74
74
|
network. Those are gated by the `plugins_io:` config keys —
|
|
75
75
|
the network is `disabled` by default, and a plugin can read
|
|
76
76
|
only the paths you list. See
|
|
77
|
-
[Configuration](03-configuration.md).
|
|
77
|
+
[Configuration](03-configuration.md). If a plugin's read falls
|
|
78
|
+
outside every configured path — a path spelled through a symlink
|
|
79
|
+
alias where the read roots hold the real path (macOS' `/tmp` is
|
|
80
|
+
one), or a genuinely out-of-tree file — Rigor surfaces a
|
|
81
|
+
`plugin_trust.read-refused` `:info` diagnostic naming the plugin,
|
|
82
|
+
the refused path and the nearest read root instead of failing
|
|
83
|
+
silently. Spell the path the way the diagnostic's read root spells
|
|
84
|
+
it, or add it under `plugins_io.allowed_paths:`.
|
|
78
85
|
|
|
79
86
|
### Isolation strategy
|
|
80
87
|
|
|
81
88
|
A few plugins call into their target library directly (for
|
|
82
89
|
example to ask ActiveSupport's real inflector how to pluralise a
|
|
83
90
|
class name). That call runs under an **isolation strategy**, set
|
|
84
|
-
with the `
|
|
91
|
+
with the `plugins_isolation:` configuration key or the
|
|
92
|
+
`RIGOR_PLUGIN_ISOLATION` environment variable:
|
|
85
93
|
|
|
86
94
|
| Value | Behaviour |
|
|
87
95
|
| --- | --- |
|
|
88
96
|
| `process` (default) | Run the call in a forked, crash-contained worker, so the target library's monkey-patches and any crash never contaminate Rigor. Falls back to `none` where `fork` is unavailable (Windows / JRuby). |
|
|
89
97
|
| `none` | Load the library into Rigor's own process and call it directly. |
|
|
90
|
-
| `ruby_box` | Run inside an experimental `Ruby::Box` sandbox. This needs the `RUBY_BOX=1` start flag, so the `rigor` launcher re-execs itself with it set when you select this strategy. |
|
|
98
|
+
| `ruby_box` | Run inside an experimental `Ruby::Box` sandbox. This needs the `RUBY_BOX=1` start flag, so the `rigor` launcher re-execs itself with it set when you select this strategy. It also needs a Ruby that fixes [Ruby Bug #22260](https://bugs.ruby-lang.org/issues/22260), which no release up to 4.0.7 does. The launcher checks for the fix first, and without it prints a warning and uses the configured strategy instead. **Environment variable only** — the configuration file is read long after Ruby has booted, so `plugins_isolation: ruby_box` is reported as a configuration error instead. |
|
|
91
99
|
|
|
92
|
-
The
|
|
93
|
-
|
|
100
|
+
The environment variable wins over `plugins_isolation:`, so you can
|
|
101
|
+
override a project's committed choice for one invocation. The legacy
|
|
102
|
+
`RIGOR_BOX` environment variable is a back-compat alias for
|
|
103
|
+
`RIGOR_PLUGIN_ISOLATION=ruby_box`. The default
|
|
94
104
|
(`process`) is the right choice for almost everyone; the variable
|
|
95
105
|
exists for the rare platform where forking is unavailable or
|
|
96
106
|
where you want stronger containment.
|
data/docs/manual/08-skills.md
CHANGED
|
@@ -8,9 +8,9 @@ agent works inside a project that has Rigor available.
|
|
|
8
8
|
Skills are optional. Everything they do, you can do by hand with the
|
|
9
9
|
commands in this manual; a skill drives the workflow end to end.
|
|
10
10
|
|
|
11
|
-
## Start here —
|
|
11
|
+
## Start here — three skills to remember
|
|
12
12
|
|
|
13
|
-
You only ever need to remember
|
|
13
|
+
You only ever need to remember three skills; the rest are reached through
|
|
14
14
|
them.
|
|
15
15
|
|
|
16
16
|
- **`rigor-next-steps`** — *"what should we do next?"* The single entry
|
|
@@ -31,6 +31,20 @@ them.
|
|
|
31
31
|
code, runs `rigor check` / `annotate` / `type-of` — then answers from
|
|
32
32
|
the page or the inferred type. You never have to remember the command,
|
|
33
33
|
just the question. Available at any point.
|
|
34
|
+
- **`rigor-type-oracle`** — *"before you write a type, ask Rigor."* The
|
|
35
|
+
one to remember while **writing** rather than while planning. Any time
|
|
36
|
+
a type is about to be written or asserted — RBS under `sig/`, an inline
|
|
37
|
+
`#:` / `# @rbs` annotation, a Sorbet `sig`, a YARD `@param` /
|
|
38
|
+
`@return`, a type named in a doc sentence or a review comment, a nil
|
|
39
|
+
check justified by "this should be an `X`" — the type comes from
|
|
40
|
+
[`rigor type-of`](02-cli-reference.md#rigor-type-of) /
|
|
41
|
+
[`annotate`](02-cli-reference.md#rigor-annotate) /
|
|
42
|
+
[`sig-gen`](02-cli-reference.md#rigor-sig-gen), not from reading the
|
|
43
|
+
code. A type nobody obtained from Rigor is a guess, and where Rigor has
|
|
44
|
+
no answer (`Dynamic[top]`, `untyped`, a skipped method) the gap is
|
|
45
|
+
reported rather than filled in. It also ships the paragraph to keep in
|
|
46
|
+
your `AGENTS.md` / `CLAUDE.md`, so the rule holds in every agent
|
|
47
|
+
session and not only when the skill triggers.
|
|
34
48
|
|
|
35
49
|
If you do not know which skill you need, start with `rigor-next-steps`.
|
|
36
50
|
|
|
@@ -72,6 +86,13 @@ is not repeated here.)
|
|
|
72
86
|
- **`rigor-monkeypatch-resolve`** — resolves an `undefined-method`
|
|
73
87
|
cluster that is really your project's own monkey-patches by wiring the
|
|
74
88
|
defining files into `pre_eval:`.
|
|
89
|
+
- **`rigor-type-oracle`** — sources every type an agent writes from
|
|
90
|
+
Rigor (`type-of` / `annotate` / `sig-gen`) instead of from reading the
|
|
91
|
+
code, and reports the gaps rather than filling them. It is triggered by
|
|
92
|
+
the *event* of a type being about to be written, so `rigor skill
|
|
93
|
+
describe` lists it but never routes to it — reach for it (or install
|
|
94
|
+
its `AGENTS.md` paragraph) whenever an agent documents or annotates
|
|
95
|
+
your code. Introduced above under "Start here".
|
|
75
96
|
|
|
76
97
|
### Integration and operations
|
|
77
98
|
|
|
@@ -358,8 +358,9 @@ Generate RBS skeleton signatures inferred from Ruby source files.
|
|
|
358
358
|
| `params` | `"untyped"` \| `"observed"` | no | `"untyped"` |
|
|
359
359
|
| `config` | `string` | no | session default |
|
|
360
360
|
|
|
361
|
-
`params: "observed"` harvests call-site argument types from
|
|
362
|
-
|
|
361
|
+
`params: "observed"` harvests call-site argument types from the
|
|
362
|
+
project's test roots: the configured `test_paths:`, or whichever of
|
|
363
|
+
`spec/` and `test/` exist.
|
|
363
364
|
|
|
364
365
|
**Returns:** JSON — the same as `rigor sig-gen --print --format json`.
|
|
365
366
|
|
data/docs/manual/11-ci.md
CHANGED
|
@@ -187,6 +187,15 @@ Rigor's severities map per format ([ADR-51](../adr/51-ci-diagnostic-output-forma
|
|
|
187
187
|
The exit code is unchanged by `--format` — `0` when there are no errors,
|
|
188
188
|
`1` otherwise — so the job still gates the pipeline. `--format json`
|
|
189
189
|
remains available for any other tool that wants the raw diagnostic stream.
|
|
190
|
+
A job that wants warnings (or `info` notes) to gate the pipeline too, not
|
|
191
|
+
just errors, raises the bar with `rigor check --fail-on=warning` (or
|
|
192
|
+
`--fail-on=info`) instead of parsing the diagnostic stream itself.
|
|
193
|
+
|
|
194
|
+
A third status, `70`, means Rigor itself died mid-run — a
|
|
195
|
+
`SystemStackError` or `NoMemoryError` inside the analysis — and the report
|
|
196
|
+
it left behind (an empty `triage.json`, say) is not an account of your
|
|
197
|
+
code. Treat it as a failed job and report it as a Rigor defect, never as a
|
|
198
|
+
clean check.
|
|
190
199
|
|
|
191
200
|
## Gating effect drift
|
|
192
201
|
|
|
@@ -337,6 +337,14 @@ ones a type actually catches.
|
|
|
337
337
|
> point Rigor at it with `bundler.bundle_path:`. Until you do, these
|
|
338
338
|
> holes keep the generic `engine_gap` cause instead of `add_rbs` —
|
|
339
339
|
> the label is missing, never wrong.
|
|
340
|
+
>
|
|
341
|
+
> A project with **no `Gemfile.lock`** is not left out: Rigor falls
|
|
342
|
+
> back to the gems it can see installed — the project's Bundler
|
|
343
|
+
> install tree if one resolves, otherwise the running Ruby's gems —
|
|
344
|
+
> and attributes constants against those. Ownership is still
|
|
345
|
+
> established by reading the gem's own entry file, so the fallback
|
|
346
|
+
> widens which gems can be claimed and never whether an unowned
|
|
347
|
+
> constant is.
|
|
340
348
|
|
|
341
349
|
Provenance is precision-additive only: it never changes a type, fires
|
|
342
350
|
no diagnostic, and never affects severity or the protection ratio.
|
|
@@ -22,25 +22,56 @@ The plain `() -> String` stays the compatibility contract; the
|
|
|
22
22
|
annotation tells Rigor the return is a non-empty string.
|
|
23
23
|
|
|
24
24
|
You may also write any of them **in a `.rb` file**, as an
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
inline-RBS comment — `%a{}` is RBS's own annotation grammar, and
|
|
26
|
+
the annotation reaches Rigor on the same path the generated
|
|
27
|
+
signature does. Rigor reads three spellings:
|
|
28
28
|
|
|
29
29
|
```rb
|
|
30
30
|
# rbs_inline: enabled
|
|
31
31
|
|
|
32
32
|
class Reader
|
|
33
|
+
# Own line: the annotation, then the type on its own tag.
|
|
33
34
|
# @rbs %a{rigor:v1:return: non-empty-string}
|
|
34
35
|
# @rbs return: String
|
|
35
36
|
def read_name = "x"
|
|
37
|
+
|
|
38
|
+
# Same line, `@rbs` method type.
|
|
39
|
+
# @rbs %a{rigor:v1:return: non-empty-string} () -> String
|
|
40
|
+
def title = "x"
|
|
41
|
+
|
|
42
|
+
# Same line, `#:` method type.
|
|
43
|
+
#: %a{rigor:v1:return: non-empty-string} () -> String
|
|
44
|
+
def label = "x"
|
|
36
45
|
end
|
|
37
46
|
```
|
|
38
47
|
|
|
48
|
+
Several annotations may stand before the method type
|
|
49
|
+
(`#: %a{pure} %a{rigor:v1:return: non-empty-string} () -> String`).
|
|
50
|
+
The other inline-RBS readers do not accept all three:
|
|
51
|
+
|
|
52
|
+
| spelling | rbs's built-in inline parser, Steep with `inline: true` | the `rbs-inline` gem's own `--output` |
|
|
53
|
+
| --- | --- | --- |
|
|
54
|
+
| own line | syntax error (`expected a token pARROW`), annotation lost | annotation kept |
|
|
55
|
+
| same line | annotation and method type kept | annotation kept, method type **dropped** |
|
|
56
|
+
|
|
57
|
+
Rigor keeps both halves of every row. If you also run Steep in
|
|
58
|
+
inline mode, use the same-line spelling. The measurement is in
|
|
59
|
+
[ADR-111](../adr/111-inline-refinement-carrier.md). If the method type after a same-line annotation
|
|
60
|
+
does not parse, the method is left untyped and Rigor reports it as
|
|
61
|
+
[`plugin.rbs-inline.source-rbs-annotation-not-honoured`](plugins/rigor-rbs-inline.md#same-line-annotations).
|
|
62
|
+
|
|
39
63
|
This needs the `rbs-inline` library installed; Rigor ingests
|
|
40
64
|
inline annotations by default when it is
|
|
41
|
-
([ADR-93](../adr/93-default-rbs-inline-ingestion.md)).
|
|
42
|
-
|
|
43
|
-
|
|
65
|
+
([ADR-93](../adr/93-default-rbs-inline-ingestion.md)). `# rigor:`
|
|
66
|
+
comments remain suppression-only.
|
|
67
|
+
|
|
68
|
+
A dedicated `# @extrbs` comment for what RBS cannot spell is
|
|
69
|
+
accepted in [ADR-112](../adr/112-extrbs-comment-channel.md) but
|
|
70
|
+
not implemented yet ([#1073](https://github.com/rigortype/rigor/issues/1073)).
|
|
71
|
+
Until it ships, the `%a{}` forms above are the inline route. A type
|
|
72
|
+
plain RBS can spell, such as `:asc | :desc`, belongs in `# @rbs` or
|
|
73
|
+
`#:` either way.
|
|
74
|
+
|
|
44
75
|
This page is the *operational* reference — the directives you can
|
|
45
76
|
write and their syntax. For the normative rules (conflict
|
|
46
77
|
handling, merging, provenance) see
|
|
@@ -122,7 +153,12 @@ The right-hand side of `return:`, `param:`, `assert*`, and
|
|
|
122
153
|
|
|
123
154
|
Refinement payloads support the parameterised forms
|
|
124
155
|
`non-empty-array[Integer]`, `non-empty-hash[Symbol, Integer]`,
|
|
125
|
-
and the bounded
|
|
156
|
+
and the bounded numeric forms `Integer[1..10]` and
|
|
157
|
+
`Float[0.0...1.0]`, written with a Ruby range literal (`1...10`,
|
|
158
|
+
`1..`, `..10`; the PHPStan-style `int<1, 10>` still parses but is
|
|
159
|
+
deprecated and reports `dynamic.rbs-extended.deprecated-form` with
|
|
160
|
+
the spelling to write), plus the Float names `non-nan-float` and
|
|
161
|
+
`finite-float`. Type-argument
|
|
126
162
|
positions also accept Symbol / String literal tokens and unions
|
|
127
163
|
of them — `pick_of[T, :name | :email]`,
|
|
128
164
|
`Pick[T, "name" | "email"]` — each lifted to a `Constant<value>`.
|
|
@@ -178,7 +214,9 @@ class UserRepository
|
|
|
178
214
|
end
|
|
179
215
|
```
|
|
180
216
|
|
|
181
|
-
The same two work as rbs-inline comments in a `.rb` file
|
|
217
|
+
The same two work as rbs-inline comments in a `.rb` file, in any of
|
|
218
|
+
the three spellings shown above — the own-line
|
|
219
|
+
one here:
|
|
182
220
|
|
|
183
221
|
```rb
|
|
184
222
|
# rbs_inline: enabled
|