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
data/lib/rigor/environment.rb
CHANGED
|
@@ -13,8 +13,10 @@ require_relative "environment/constant_type_cache_holder"
|
|
|
13
13
|
require_relative "environment/missing_gem_constant_index"
|
|
14
14
|
require_relative "environment/bundle_sig_discovery"
|
|
15
15
|
require_relative "environment/lockfile_resolver"
|
|
16
|
+
require_relative "environment/installed_gem_set"
|
|
16
17
|
require_relative "environment/rbs_collection_discovery"
|
|
17
18
|
require_relative "plugin/isolation"
|
|
19
|
+
require_relative "cache/engine_source"
|
|
18
20
|
require_relative "environment/rbs_coverage_report"
|
|
19
21
|
require_relative "inference/synthetic_method_index"
|
|
20
22
|
require_relative "inference/project_patched_methods"
|
|
@@ -48,16 +50,15 @@ module Rigor
|
|
|
48
50
|
:reporters, :name_scope,
|
|
49
51
|
:synthetic_method_index, :project_patched_methods
|
|
50
52
|
|
|
51
|
-
# @param
|
|
52
|
-
# @param rbs_loader [Rigor::Environment::RbsLoader, nil] when nil the environment is "RBS-blind"; useful
|
|
53
|
+
# @param rbs_loader — when nil the environment is "RBS-blind"; useful
|
|
53
54
|
# in tests that want to assert how the engine behaves without RBS data. The default Environment wires
|
|
54
55
|
# the shared core loader, which is itself lazy: requesting an environment instance does NOT load RBS
|
|
55
56
|
# until a method or class query actually consults the loader.
|
|
56
|
-
# @param plugin_registry
|
|
57
|
+
# @param plugin_registry — v0.1.1 Track 2 slice 7. The per-run plugin
|
|
57
58
|
# registry the inference engine consults at call sites for plugin `dynamic_return` rules. When nil
|
|
58
59
|
# (the default), no plugin-level return-type contribution participates — useful for tests, the
|
|
59
60
|
# `Environment.default` facade, and analyses that don't load plugins.
|
|
60
|
-
# @param dependency_source_index
|
|
61
|
+
# @param dependency_source_index — ADR-10 slice
|
|
61
62
|
# 2b-ii. The per-run index of opt-in gem sources the dispatcher consults BELOW RBS dispatch. When nil
|
|
62
63
|
# (the default), no dep-source contribution participates and the dispatcher tier is a no-op.
|
|
63
64
|
def initialize(class_registry: ClassRegistry.default, rbs_loader: nil, # rubocop:disable Metrics/ParameterLists
|
|
@@ -151,7 +152,7 @@ module Rigor
|
|
|
151
152
|
# defect. First-write-wins on the slot means a run whose overlay AND scan both raise reports the
|
|
152
153
|
# overlay — the actionable one, since the plugin is what a user can remove.
|
|
153
154
|
#
|
|
154
|
-
# @return
|
|
155
|
+
# @return the registry the RBS scan is layered on top of.
|
|
155
156
|
def pre_scan_hkt_registry
|
|
156
157
|
return @hkt_registry_base unless @plugin_registry.respond_to?(:hkt_overlay_registry)
|
|
157
158
|
|
|
@@ -171,8 +172,6 @@ module Rigor
|
|
|
171
172
|
# worker (the coordinator never analyses a file under the pool, so the drain is how its snapshot learns
|
|
172
173
|
# the outcome: the #696 lesson), and from a resolved environment when the analyze set is empty — so the
|
|
173
174
|
# row never depends on which files happened to be analysed.
|
|
174
|
-
#
|
|
175
|
-
# @return [Array(String, String, String, Symbol), Array(String, String, nil, Symbol), nil]
|
|
176
175
|
def hkt_scan_failure
|
|
177
176
|
@hkt_scan_failure.value
|
|
178
177
|
end
|
|
@@ -255,18 +254,17 @@ module Rigor
|
|
|
255
254
|
# Builds an Environment that consults the project's local signatures and any opt-in stdlib libraries on
|
|
256
255
|
# top of RBS core.
|
|
257
256
|
#
|
|
258
|
-
# @param root
|
|
257
|
+
# @param root — project root used to auto-detect the default signature path. Defaults
|
|
259
258
|
# to the current working directory.
|
|
260
|
-
# @param libraries
|
|
259
|
+
# @param libraries — additional stdlib libraries to load on top of
|
|
261
260
|
# {DEFAULT_LIBRARIES}. The final list is the union of the two, de-duplicated while preserving order.
|
|
262
261
|
# Pass an empty array (the default) to load only the defaults.
|
|
263
|
-
# @param signature_paths
|
|
262
|
+
# @param signature_paths — explicit list of `sig/`-style directories. When
|
|
264
263
|
# `nil` (the default), the canonical project layout `<root>/sig` is used if it exists, otherwise no
|
|
265
264
|
# signature path is loaded.
|
|
266
|
-
# @param cache_store
|
|
265
|
+
# @param cache_store — persistent cache threaded into the underlying
|
|
267
266
|
# {Environment::RbsLoader} so constant lookups (and, in later v0.0.9 slices, other reflection
|
|
268
267
|
# artefacts) consult the cache. Pass `nil` (the default) to skip caching for this environment.
|
|
269
|
-
# @return [Rigor::Environment]
|
|
270
268
|
# rubocop:disable-next Metrics/MethodLength, Metrics/ParameterLists
|
|
271
269
|
def for_project(root: Dir.pwd, libraries: [], signature_paths: nil, cache_store: nil,
|
|
272
270
|
plugin_registry: nil, dependency_source_index: nil,
|
|
@@ -276,7 +274,7 @@ module Rigor
|
|
|
276
274
|
bundler_lockfile: nil,
|
|
277
275
|
rbs_collection_lockfile: nil, rbs_collection_auto_detect: false,
|
|
278
276
|
synthetic_method_index: nil, project_patched_methods: nil,
|
|
279
|
-
source_files: [])
|
|
277
|
+
source_files: [], locked_gems: nil)
|
|
280
278
|
resolved_paths = signature_paths || default_signature_paths(root)
|
|
281
279
|
# O4 MVP — append per-gem `sig/` directories discovered under the target project's bundler install
|
|
282
280
|
# root. Empty array when neither an explicit path nor auto-detection finds a bundle. Order: user
|
|
@@ -287,7 +285,10 @@ module Rigor
|
|
|
287
285
|
# to the project root), use the locked gem set to filter the discovered `sig/` directories. Stale
|
|
288
286
|
# gems in the bundle install tree (out-of-band installs, version drift after a `bundle update`) are
|
|
289
287
|
# silently dropped so only gems the project actually declares contribute RBS.
|
|
290
|
-
|
|
288
|
+
#
|
|
289
|
+
# #1064 — `locked_gems:` is that same map resolved by the caller. The Ractor pool passes it because
|
|
290
|
+
# Bundler's parser cannot run in a non-main Ractor; every other caller leaves it nil and resolves here.
|
|
291
|
+
locked = locked_gems || LockfileResolver.locked_gems(
|
|
291
292
|
lockfile_path: bundler_lockfile,
|
|
292
293
|
project_root: root,
|
|
293
294
|
auto_detect: bundler_auto_detect
|
|
@@ -336,7 +337,7 @@ module Rigor
|
|
|
336
337
|
missing_gems, overlay_paths = missing_gems_and_overlay_paths(
|
|
337
338
|
locked: locked, default_libraries: merged_libraries, bundle_sig_paths: gem_sig_paths,
|
|
338
339
|
rbs_collection_paths: collection_paths, plugin_registry: plugin_registry,
|
|
339
|
-
signature_paths: resolved_paths
|
|
340
|
+
signature_paths: resolved_paths, bundle_root: bundle_root
|
|
340
341
|
)
|
|
341
342
|
loader_signature_paths = resolved_paths + plugin_sig_paths + gem_sig_paths +
|
|
342
343
|
collection_paths + overlay_paths
|
|
@@ -361,6 +362,14 @@ module Rigor
|
|
|
361
362
|
# the bundle walk and `rbs collection install` all stay authoritative.
|
|
362
363
|
deferred_signature_paths: plugin_sig_paths
|
|
363
364
|
)
|
|
365
|
+
# Issues #824 / #1075 — the rows ADR-112 WD5's consistency rule reports for members the project's
|
|
366
|
+
# own `sig/` and an inline source both declare: an error per contradiction (or per refinement that
|
|
367
|
+
# exceeds its own declared type), an `:info` per inline member dropped undecided. Recorded HERE
|
|
368
|
+
# because this is where the reporter is: the run's `source_rbs_synthesis` stream already carries
|
|
369
|
+
# WD12's "parsed but not honoured" rows, drains out of pool workers, and is regenerated (never cached)
|
|
370
|
+
# on every run, so the member-level outcome needs no plumbing of its own. Costs nothing for a project
|
|
371
|
+
# with no inline RBS: the loader's reader short-circuits on an empty `virtual_rbs`.
|
|
372
|
+
record_member_consistency(loader, source_rbs_synthesis_reporter, root)
|
|
364
373
|
# ADR-20 slice 2c + 2e — seed hkt_registry with the bundled builtins. The Environment's
|
|
365
374
|
# `#hkt_registry` getter then LAZILY merges in the RBS env scan on first call so fast paths that
|
|
366
375
|
# don't consult HKT (e.g. `rigor check --cache-stats --no-stats`) don't pay the eager env-build cost
|
|
@@ -412,13 +421,13 @@ module Rigor
|
|
|
412
421
|
# and consumed twice: as `[gem_name, version]` pairs for the ADR-82 WD9 constant-ownership index, and
|
|
413
422
|
# as the eligible-gem set for the ADR-72 overlay resolution. Returns `[pairs, overlay_paths]`.
|
|
414
423
|
def missing_gems_and_overlay_paths(locked:, default_libraries:, bundle_sig_paths:,
|
|
415
|
-
rbs_collection_paths:, plugin_registry:, signature_paths: []
|
|
416
|
-
|
|
424
|
+
rbs_collection_paths:, plugin_registry:, signature_paths: [],
|
|
425
|
+
bundle_root: nil)
|
|
426
|
+
if locked.empty?
|
|
427
|
+
return unlocked_missing_gems(default_libraries, bundle_sig_paths, rbs_collection_paths, bundle_root)
|
|
428
|
+
end
|
|
417
429
|
|
|
418
|
-
rows =
|
|
419
|
-
locked_gems: locked, default_libraries: default_libraries,
|
|
420
|
-
bundle_sig_paths: bundle_sig_paths, rbs_collection_paths: rbs_collection_paths
|
|
421
|
-
).select { |row| row.source == :missing }
|
|
430
|
+
rows = missing_rows(locked, default_libraries, bundle_sig_paths, rbs_collection_paths)
|
|
422
431
|
overlays = gem_overlay_paths(
|
|
423
432
|
missing_gem_names: rows.map(&:gem_name), plugin_registry: plugin_registry,
|
|
424
433
|
signature_paths: signature_paths
|
|
@@ -426,6 +435,27 @@ module Rigor
|
|
|
426
435
|
[rows.map { |row| [row.gem_name, row.version] }, overlays]
|
|
427
436
|
end
|
|
428
437
|
|
|
438
|
+
# Issue #530 — a project with no `Gemfile.lock` still has gems on disk, and before this it handed the
|
|
439
|
+
# ADR-82 WD9 index nothing, so every constant reaching into an RBS-less gem kept the generic cause and
|
|
440
|
+
# the whole boundary reported as `engine_gap` rather than `add_rbs`. The installed set stands in for
|
|
441
|
+
# the locked one ({InstalledGemSet} says why that stays honest), and only for the provenance index:
|
|
442
|
+
# the second element is always empty because the ADR-72 overlays change what type-checks and so remain
|
|
443
|
+
# gated on the project's own declaration.
|
|
444
|
+
def unlocked_missing_gems(default_libraries, bundle_sig_paths, rbs_collection_paths, bundle_root)
|
|
445
|
+
installed = InstalledGemSet.gems(bundle_path: bundle_root)
|
|
446
|
+
return [[], []] if installed.empty?
|
|
447
|
+
|
|
448
|
+
rows = missing_rows(installed, default_libraries, bundle_sig_paths, rbs_collection_paths)
|
|
449
|
+
[rows.map { |row| [row.gem_name, row.version] }, []]
|
|
450
|
+
end
|
|
451
|
+
|
|
452
|
+
def missing_rows(gems, default_libraries, bundle_sig_paths, rbs_collection_paths)
|
|
453
|
+
RbsCoverageReport.classify(
|
|
454
|
+
locked_gems: gems, default_libraries: default_libraries,
|
|
455
|
+
bundle_sig_paths: bundle_sig_paths, rbs_collection_paths: rbs_collection_paths
|
|
456
|
+
).select { |row| row.source == :missing }
|
|
457
|
+
end
|
|
458
|
+
|
|
429
459
|
# ADR-72 — resolve the bundled RBS overlay directories to load for this project. A gem is eligible when
|
|
430
460
|
# it is classified `:missing` (see {missing_rbs_gem_rows}) and its conflicting opt-in plugin twin (if
|
|
431
461
|
# any) is NOT already reachable. Returns `[Pathname]`, deterministically ordered, or `[]` when no
|
|
@@ -467,7 +497,10 @@ module Rigor
|
|
|
467
497
|
#
|
|
468
498
|
# WD5 — when `cache_store` is supplied, each (file, plugin) synthesizer call is memoised through
|
|
469
499
|
# `Cache::Store`. The cache key composes the file's content SHA with the plugin's `PluginEntry` (id +
|
|
470
|
-
# version + config_hash) so a config change or content change invalidates the entry automatically
|
|
500
|
+
# version + config_hash) so a config change or content change invalidates the entry automatically, and
|
|
501
|
+
# with the engine's source identity (issue #1009): a plugin's manifest version does not move when a
|
|
502
|
+
# checkout edits its synthesizer, and a stale string here also keeps the `rbs.virtual_rbs` env key warm,
|
|
503
|
+
# so the new build's rules would read the old build's RBS.
|
|
471
504
|
def collect_virtual_rbs(plugin_registry, source_files, cache_store, reporter)
|
|
472
505
|
return [] if plugin_registry.nil?
|
|
473
506
|
|
|
@@ -498,6 +531,8 @@ module Rigor
|
|
|
498
531
|
return invoke_synthesizer_safely(callable, path) unless File.file?(path)
|
|
499
532
|
|
|
500
533
|
descriptor = build_synthesizer_cache_descriptor(plugin, path)
|
|
534
|
+
return invoke_synthesizer_safely(callable, path) if descriptor.nil?
|
|
535
|
+
|
|
501
536
|
cache_store.fetch_or_compute(
|
|
502
537
|
producer_id: SYNTHESIZER_CACHE_PRODUCER_ID,
|
|
503
538
|
params: {},
|
|
@@ -540,6 +575,93 @@ module Rigor
|
|
|
540
575
|
reporter&.record(plugin_id: plugin.manifest.id, path: path, message: message.to_s, kind: kind)
|
|
541
576
|
end
|
|
542
577
|
|
|
578
|
+
# ADR-112 WD5 / issue #1075 — turn each reported {MemberConsistency::Record} into a row on the
|
|
579
|
+
# synthesis stream. A contradiction, or a refinement outside its own declared type, is a `:contradiction`
|
|
580
|
+
# entry ({Analysis::CheckRules::RULE_CONTRADICTING_SIGNATURE}, an error), positioned at the `.rbs`
|
|
581
|
+
# member when there is one: that file is real and its line is exact, where the inline member's position
|
|
582
|
+
# lives in the synthesized RBS buffer, a document nobody has. An undecided pair keeps ADR-32 WD12's
|
|
583
|
+
# `:not_honoured` row at the annotated `.rb` (line 1, as every entry on that stream is): the inline
|
|
584
|
+
# signature was parsed and dropped, and WD12 forbids swallowing that. The silent outcomes — equal, or
|
|
585
|
+
# merged to the more precise side — record nothing.
|
|
586
|
+
#
|
|
587
|
+
# The records are derived with a {MemberConsistency::RbsProof}, so a contradiction is proven from the
|
|
588
|
+
# RBS hierarchy of core and stdlib classes, never from the analyzer process's loaded constants.
|
|
589
|
+
def record_member_consistency(loader, reporter, root)
|
|
590
|
+
return if reporter.nil?
|
|
591
|
+
|
|
592
|
+
proof = MemberConsistency::RbsProof.new(loader)
|
|
593
|
+
loader.member_consistency(proof: proof).each do |record|
|
|
594
|
+
case record.outcome
|
|
595
|
+
when :contradiction then record_member_contradiction(reporter, record, root)
|
|
596
|
+
when :refinement then record_refinement_contradiction(reporter, record, root)
|
|
597
|
+
when :undecided then record_member_undecided(reporter, record, root)
|
|
598
|
+
end
|
|
599
|
+
end
|
|
600
|
+
end
|
|
601
|
+
|
|
602
|
+
def record_member_contradiction(reporter, record, root)
|
|
603
|
+
plugin_id, path = split_virtual_source_name(record.virtual_name)
|
|
604
|
+
return if path.nil?
|
|
605
|
+
|
|
606
|
+
reporter.record(
|
|
607
|
+
plugin_id: plugin_id, path: path_relative_to(record.signature_path, root), line: record.signature_line,
|
|
608
|
+
kind: :contradiction,
|
|
609
|
+
message: "`#{member_label(record)}` is declared here and by an inline annotation in " \
|
|
610
|
+
"`#{path_relative_to(path, root)}`, and the two contradict: #{record.detail}. Rigor reads " \
|
|
611
|
+
"this `.rbs` declaration. Regenerate the signature, or fix the annotation, so that one " \
|
|
612
|
+
"of the two refines the other."
|
|
613
|
+
)
|
|
614
|
+
end
|
|
615
|
+
|
|
616
|
+
def record_refinement_contradiction(reporter, record, root)
|
|
617
|
+
plugin_id, path = split_virtual_source_name(record.virtual_name)
|
|
618
|
+
path = record.signature_path if path.nil?
|
|
619
|
+
return if path.nil?
|
|
620
|
+
|
|
621
|
+
reporter.record(
|
|
622
|
+
plugin_id: plugin_id.to_s, path: path_relative_to(path, root), line: record.signature_line,
|
|
623
|
+
kind: :contradiction,
|
|
624
|
+
message: "`#{member_label(record)}` refines its own signature to a type outside it: " \
|
|
625
|
+
"#{record.detail}. A `rigor:v1:` refinement may narrow the ordinary RBS contract, never " \
|
|
626
|
+
"contradict it, so one of the two is wrong."
|
|
627
|
+
)
|
|
628
|
+
end
|
|
629
|
+
|
|
630
|
+
def record_member_undecided(reporter, record, root)
|
|
631
|
+
plugin_id, path = split_virtual_source_name(record.virtual_name)
|
|
632
|
+
return if path.nil?
|
|
633
|
+
|
|
634
|
+
reporter.record(
|
|
635
|
+
plugin_id: plugin_id, path: path, kind: :not_honoured,
|
|
636
|
+
message: "`#{member_label(record)}` is also declared in " \
|
|
637
|
+
"`#{path_relative_to(record.signature_path, root)}`, and Rigor cannot tell which of the two " \
|
|
638
|
+
"is the more precise (#{record.detail}), so the `.rbs` declaration binds and the inline " \
|
|
639
|
+
"signature was dropped. Left to collide the two would fail the class's definition build, " \
|
|
640
|
+
"and every call on it — real methods and typos alike — would read `Dynamic[top]`. Make " \
|
|
641
|
+
"one of the two a refinement of the other, or remove one, to settle which binds."
|
|
642
|
+
)
|
|
643
|
+
end
|
|
644
|
+
|
|
645
|
+
def member_label(record)
|
|
646
|
+
separator = record.kind == :singleton ? "." : "#"
|
|
647
|
+
"#{record.class_name}#{separator}#{record.method_name}"
|
|
648
|
+
end
|
|
649
|
+
|
|
650
|
+
# Splits a virtual buffer name back into the pair {.collect_virtual_rbs} composed it from
|
|
651
|
+
# (`virtual:<plugin id>:<source path>`). Limited to three fields so a path carrying a colon survives.
|
|
652
|
+
# Returns `[nil, nil]` for a name in any other shape — a synthesizer channel this method does not own.
|
|
653
|
+
def split_virtual_source_name(virtual_name)
|
|
654
|
+
prefix, plugin_id, path = virtual_name.to_s.split(":", 3)
|
|
655
|
+
return [nil, nil] unless prefix == "virtual" && plugin_id && !plugin_id.empty? && path && !path.empty?
|
|
656
|
+
|
|
657
|
+
[plugin_id, path]
|
|
658
|
+
end
|
|
659
|
+
|
|
660
|
+
def path_relative_to(path, root)
|
|
661
|
+
prefix = "#{root}#{File::SEPARATOR}"
|
|
662
|
+
path.to_s.start_with?(prefix) ? path.to_s.delete_prefix(prefix) : path.to_s
|
|
663
|
+
end
|
|
664
|
+
|
|
543
665
|
SYNTHESIZER_CACHE_PRODUCER_ID = "plugin.source_rbs_synthesizer"
|
|
544
666
|
private_constant :SYNTHESIZER_CACHE_PRODUCER_ID
|
|
545
667
|
|
|
@@ -558,8 +680,13 @@ module Rigor
|
|
|
558
680
|
comparator: :digest,
|
|
559
681
|
value: synthesizer_input_digest(path)
|
|
560
682
|
)],
|
|
561
|
-
plugins: [plugin.plugin_entry]
|
|
683
|
+
plugins: [plugin.plugin_entry],
|
|
684
|
+
configs: Cache::EngineSource.key_config_entries
|
|
562
685
|
)
|
|
686
|
+
rescue Cache::EngineSource::Unavailable
|
|
687
|
+
# An engine that cannot be identified must not be keyed by its inputs alone (issue #1009): nil runs the
|
|
688
|
+
# synthesizer uncached rather than serving an entry another build may have written.
|
|
689
|
+
nil
|
|
563
690
|
end
|
|
564
691
|
|
|
565
692
|
def synthesizer_input_digest(path)
|
|
@@ -623,6 +750,17 @@ module Rigor
|
|
|
623
750
|
end
|
|
624
751
|
end
|
|
625
752
|
|
|
753
|
+
# Issue #1362 — the translated type of the RBS declaration of the global variable `name` (`$stdout: IO` answers
|
|
754
|
+
# `Nominal[IO]`), or nil when no signature declares it or the environment carries no RBS loader. With
|
|
755
|
+
# `builtin: true` it answers only for a declaration in Ruby's own core or stdlib signatures, a global the
|
|
756
|
+
# interpreter sets; a project's or a gem's declaration then answers nil.
|
|
757
|
+
def global_for_name(name, builtin: false)
|
|
758
|
+
return nil if rbs_loader.nil?
|
|
759
|
+
return nil if builtin && !rbs_loader.core_or_stdlib_global?(name)
|
|
760
|
+
|
|
761
|
+
rbs_loader.global_type(name)
|
|
762
|
+
end
|
|
763
|
+
|
|
626
764
|
# Returns true when the constant name is known to either the static registry or the RBS loader. Useful
|
|
627
765
|
# for callers that only need a presence check without materialising a type carrier.
|
|
628
766
|
def class_known?(name)
|
|
@@ -653,6 +791,15 @@ module Rigor
|
|
|
653
791
|
rbs_loader.rbs_module?(name)
|
|
654
792
|
end
|
|
655
793
|
|
|
794
|
+
# Issue #915 — the module names RBS puts in `name`'s SINGLETON ancestry, the declaration-side twin of
|
|
795
|
+
# `Scope#singleton_extends_of`. `Inference::Narrowing` reads it the same one-directional way: presence
|
|
796
|
+
# withholds a `Bot`, absence asserts nothing (a class the environment does not know answers `[]`).
|
|
797
|
+
def singleton_extended_modules(name)
|
|
798
|
+
return [] unless rbs_loader
|
|
799
|
+
|
|
800
|
+
rbs_loader.singleton_extended_module_names(normalize_class_name(name))
|
|
801
|
+
end
|
|
802
|
+
|
|
656
803
|
# Compares two class/module names using analyzer-owned class data. Returns `:equal`, `:subclass`,
|
|
657
804
|
# `:superclass`, `:disjoint`, or `:unknown`. The static registry handles built-ins cheaply; the RBS
|
|
658
805
|
# loader handles project/stdlib classes without relying on host Ruby constants being loaded.
|
|
@@ -677,8 +824,11 @@ module Rigor
|
|
|
677
824
|
rbs_loader.class_known?(name)
|
|
678
825
|
end
|
|
679
826
|
|
|
827
|
+
# Allocates only when there is a prefix to strip: `String#delete_prefix` copies unconditionally, and
|
|
828
|
+
# this runs once per class-registry / hierarchy probe (~320k times on the lib self-check).
|
|
680
829
|
def normalize_class_name(name)
|
|
681
|
-
name.to_s
|
|
830
|
+
name = name.to_s
|
|
831
|
+
name.start_with?("::") ? name.delete_prefix("::") : name
|
|
682
832
|
end
|
|
683
833
|
|
|
684
834
|
# ADR-13 slice 3b — composes the per-run plugin-supplied {Rigor::TypeNode::ResolverChain} into a single
|
|
@@ -49,24 +49,24 @@ module Rigor
|
|
|
49
49
|
|
|
50
50
|
attr_reader(*SLOT_NAMES, :provenance)
|
|
51
51
|
|
|
52
|
-
# @param return_type
|
|
52
|
+
# @param return_type — normal-edge return type. Use `nil` when the contribution does not
|
|
53
53
|
# refine the return type selected from the RBS contract.
|
|
54
|
-
# @param truthy_facts
|
|
54
|
+
# @param truthy_facts — facts that hold only on the truthy control-flow edge. Edge-local: a
|
|
55
55
|
# truthy-edge fact does NOT imply its falsey-edge complement (ADR-2 § "Plugin Contribution Merging").
|
|
56
|
-
# @param falsey_facts
|
|
57
|
-
# @param post_return_facts
|
|
56
|
+
# @param falsey_facts — dual of `truthy_facts`.
|
|
57
|
+
# @param post_return_facts — facts that hold after the call returns normally on every edge —
|
|
58
58
|
# the carrier for assertion-style contributions.
|
|
59
|
-
# @param mutations
|
|
60
|
-
# @param invalidations
|
|
59
|
+
# @param mutations — receiver and argument mutation effects.
|
|
60
|
+
# @param invalidations — targeted fact invalidations beyond what mutation effects already
|
|
61
61
|
# imply.
|
|
62
|
-
# @param exceptional
|
|
63
|
-
# @param role_conformance
|
|
64
|
-
# @param effects
|
|
62
|
+
# @param exceptional — non-returning, raising, or unreachable effect.
|
|
63
|
+
# @param role_conformance — capability-role conformance facts the contribution provides.
|
|
64
|
+
# @param effects — ADR-103 WD5 — the effect labels this call edge
|
|
65
65
|
# attributes to its callee, as an upper bound. `nil` means "says nothing about effects", which is
|
|
66
66
|
# NOT the same as the empty set (which asserts the call performs none). Merged by union, the
|
|
67
67
|
# conservative direction: two sources that each name part of a call's footprint together name
|
|
68
68
|
# more of it, and neither can shrink the other's claim.
|
|
69
|
-
# @param provenance
|
|
69
|
+
# @param provenance — source-family, plugin-id, node, and cache-descriptor metadata. Defaults
|
|
70
70
|
# to `Provenance.builtin`.
|
|
71
71
|
# rubocop:disable Metrics/ParameterLists
|
|
72
72
|
def initialize(return_type: nil, truthy_facts: nil, falsey_facts: nil,
|
|
@@ -87,7 +87,7 @@ module Rigor
|
|
|
87
87
|
freeze
|
|
88
88
|
end
|
|
89
89
|
|
|
90
|
-
# @return
|
|
90
|
+
# @return true when every content slot is unset (nil or an empty collection). Provenance does
|
|
91
91
|
# not count toward emptiness — an empty bundle still carries source attribution.
|
|
92
92
|
def empty?
|
|
93
93
|
SLOT_NAMES.all? { |slot| slot_empty?(slot, public_send(slot)) }
|
|
@@ -116,8 +116,6 @@ module Rigor
|
|
|
116
116
|
# | exceptional | exceptional | exception | :raise |
|
|
117
117
|
# | role_conformance | normal | role | (per-role target) |
|
|
118
118
|
# | effects | normal | effects | :effects |
|
|
119
|
-
#
|
|
120
|
-
# @return [Array<Element>]
|
|
121
119
|
def to_element_list # rubocop:disable Metrics/AbcSize
|
|
122
120
|
elements = []
|
|
123
121
|
elements << element_for(:return, :normal, :return_type, return_type) unless return_type.nil?
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Rigor
|
|
4
|
+
module Hashing
|
|
5
|
+
# Pure-Ruby XXH3-64 (seed 0, default secret) — the content hash for the `rigor lens` anchors of
|
|
6
|
+
# ADR-113 WD6, landed ahead of `rigor lens` itself (#1083). A port of the upstream xxHash scalar
|
|
7
|
+
# path (`xxhash.h`'s `XXH3_64bits` with `XXH3_kSecret`), pinned by the upstream sanity-check
|
|
8
|
+
# vectors and cross-checked against lisplens's `xxhash-rust` output; see
|
|
9
|
+
# `spec/rigor/hashing/xxh3_spec.rb`.
|
|
10
|
+
#
|
|
11
|
+
# Pure Ruby per ADR-31: a native `xxhash` gem is a supply-chain addition to hash a few hundred
|
|
12
|
+
# bytes per call. Only the seedless/default-secret variant is implemented — the `rigor lens`
|
|
13
|
+
# anchors are the sole consumer, and they match lisplens ADR-0008's form exactly:
|
|
14
|
+
#
|
|
15
|
+
# - {.anchor_hash} is `xxh3_64 & 0xffff` printed as 4 lowercase hex digits (a per-row anchor).
|
|
16
|
+
# - {.file_hash} is the full 64-bit value printed as 16 lowercase hex digits (a file-level guard).
|
|
17
|
+
#
|
|
18
|
+
# Every arithmetic op below is modulo 2^64; `& MASK64` marks the spots where the C code wraps.
|
|
19
|
+
module XXH3
|
|
20
|
+
# Constant and helper names keep upstream's `xxhash.h` identifiers (PRIME64_1, accumulate_512,
|
|
21
|
+
# …) so the port stays diffable against the reference scalar path.
|
|
22
|
+
# rubocop:disable Naming/VariableNumber
|
|
23
|
+
MASK64 = (1 << 64) - 1
|
|
24
|
+
MASK32 = (1 << 32) - 1
|
|
25
|
+
|
|
26
|
+
PRIME32_1 = 0x9E3779B1
|
|
27
|
+
PRIME32_2 = 0x85EBCA77
|
|
28
|
+
PRIME32_3 = 0xC2B2AE3D
|
|
29
|
+
PRIME64_1 = 0x9E3779B185EBCA87
|
|
30
|
+
PRIME64_2 = 0xC2B2AE3D27D4EB4F
|
|
31
|
+
PRIME64_3 = 0x165667B19E3779F9
|
|
32
|
+
PRIME64_4 = 0x85EBCA77C2B2AE63
|
|
33
|
+
PRIME64_5 = 0x27D4EB2F165667C5
|
|
34
|
+
PRIME_MX1 = 0x165667919E3779F9
|
|
35
|
+
PRIME_MX2 = 0x9FB21C651E98DF25
|
|
36
|
+
|
|
37
|
+
STRIPE_LEN = 64
|
|
38
|
+
SECRET_CONSUME_RATE = 8
|
|
39
|
+
ACC_NB = STRIPE_LEN / 8
|
|
40
|
+
MIDSIZE_MAX = 240
|
|
41
|
+
SECRET_SIZE_MIN = 136
|
|
42
|
+
MIDSIZE_STARTOFFSET = 3
|
|
43
|
+
MIDSIZE_LASTOFFSET = 17
|
|
44
|
+
SECRET_LASTACC_START = 7
|
|
45
|
+
SECRET_MERGEACCS_START = 11
|
|
46
|
+
|
|
47
|
+
# `XXH3_kSecret` — the 192-byte default secret taken from FARSH, verbatim from `xxhash.h`
|
|
48
|
+
# (one hex pair per upstream byte literal).
|
|
49
|
+
SECRET = [
|
|
50
|
+
"b8fe6c3923a44bbe7c01812cf721ad1cded46de9839097db7240a4a4b7b3671f" \
|
|
51
|
+
"cb79e64eccc0e578825ad07dccff7221b8084674f743248ee03590e6813a264c" \
|
|
52
|
+
"3c2852bb91c300cb88d0658b1b532ea371644897a20df94e3819ef46a9deacd8" \
|
|
53
|
+
"a8fa763fe39c343ff9dcbbc7c70b4f1d8a51e04bcdb45931c89f7ec9d9787364" \
|
|
54
|
+
"eac5ac8334d3ebc3c581a0fffa1363eb170ddd51b7f0da49d316552629d4689e" \
|
|
55
|
+
"2b16be587d47a1fc8ff8b8d17ad031ce45cb3a8f95160428afd7fbcabb4b407e"
|
|
56
|
+
].pack("H*").freeze
|
|
57
|
+
|
|
58
|
+
# XXH3_INIT_ACC
|
|
59
|
+
INIT_ACC = [PRIME32_3, PRIME64_1, PRIME64_2, PRIME64_3, PRIME64_4, PRIME32_2, PRIME64_5, PRIME32_1].freeze
|
|
60
|
+
|
|
61
|
+
private_constant :MASK64, :MASK32, :PRIME32_1, :PRIME32_2, :PRIME32_3, :PRIME64_1, :PRIME64_2, :PRIME64_3,
|
|
62
|
+
:PRIME64_4, :PRIME64_5, :PRIME_MX1, :PRIME_MX2, :STRIPE_LEN, :SECRET_CONSUME_RATE,
|
|
63
|
+
:ACC_NB, :MIDSIZE_MAX, :SECRET_SIZE_MIN, :MIDSIZE_STARTOFFSET, :MIDSIZE_LASTOFFSET,
|
|
64
|
+
:SECRET_LASTACC_START, :SECRET_MERGEACCS_START, :SECRET, :INIT_ACC
|
|
65
|
+
|
|
66
|
+
class << self
|
|
67
|
+
# XXH3_64bits of `bytes`, hashed as raw bytes — the string's encoding is ignored.
|
|
68
|
+
def digest64(bytes)
|
|
69
|
+
len = bytes.bytesize
|
|
70
|
+
if len <= 16 then len_0to16(bytes, len)
|
|
71
|
+
elsif len <= 128 then len_17to128(bytes, len)
|
|
72
|
+
elsif len <= MIDSIZE_MAX then len_129to240(bytes, len)
|
|
73
|
+
else hash_long(bytes, len)
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# lisplens ADR-0008's `anchor_hash`: the low 16 bits of the digest as 4 lowercase hex digits.
|
|
78
|
+
def anchor_hash(bytes)
|
|
79
|
+
format("%04x", digest64(bytes) & 0xffff)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# lisplens ADR-0008's `file_hash`: the full digest as 16 lowercase hex digits.
|
|
83
|
+
def file_hash(bytes)
|
|
84
|
+
format("%016x", digest64(bytes))
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
private
|
|
88
|
+
|
|
89
|
+
# --- short keys: len <= 16 ---
|
|
90
|
+
|
|
91
|
+
def len_0to16(bytes, len)
|
|
92
|
+
if len > 8 then len_9to16(bytes, len)
|
|
93
|
+
elsif len >= 4 then len_4to8(bytes, len)
|
|
94
|
+
elsif len.positive? then len_1to3(bytes, len)
|
|
95
|
+
else
|
|
96
|
+
xxh64_avalanche(u64(SECRET, 56) ^ u64(SECRET, 64))
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def len_1to3(bytes, len)
|
|
101
|
+
c1 = bytes.getbyte(0)
|
|
102
|
+
c2 = bytes.getbyte(len >> 1)
|
|
103
|
+
c3 = bytes.getbyte(len - 1)
|
|
104
|
+
combined = (c1 << 16) | (c2 << 24) | c3 | (len << 8)
|
|
105
|
+
bitflip = u32(SECRET, 0) ^ u32(SECRET, 4)
|
|
106
|
+
xxh64_avalanche(combined ^ bitflip)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def len_4to8(bytes, len)
|
|
110
|
+
input1 = u32(bytes, 0)
|
|
111
|
+
input2 = u32(bytes, len - 4)
|
|
112
|
+
bitflip = u64(SECRET, 8) ^ u64(SECRET, 16)
|
|
113
|
+
keyed = (input2 + (input1 << 32)) ^ bitflip
|
|
114
|
+
rrmxmx(keyed, len)
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def len_9to16(bytes, len)
|
|
118
|
+
bitflip1 = u64(SECRET, 24) ^ u64(SECRET, 32)
|
|
119
|
+
bitflip2 = u64(SECRET, 40) ^ u64(SECRET, 48)
|
|
120
|
+
input_lo = u64(bytes, 0) ^ bitflip1
|
|
121
|
+
input_hi = u64(bytes, len - 8) ^ bitflip2
|
|
122
|
+
acc = (len + swap64(input_lo) + input_hi + mul128_fold64(input_lo, input_hi)) & MASK64
|
|
123
|
+
xxh3_avalanche(acc)
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
# --- mid-size keys: 17 <= len <= 240 (mum-hash on 16-byte chunks) ---
|
|
127
|
+
|
|
128
|
+
def mix16b(bytes, in_off, sec_off)
|
|
129
|
+
input_lo = u64(bytes, in_off)
|
|
130
|
+
input_hi = u64(bytes, in_off + 8)
|
|
131
|
+
mul128_fold64(input_lo ^ u64(SECRET, sec_off), input_hi ^ u64(SECRET, sec_off + 8))
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def len_17to128(bytes, len)
|
|
135
|
+
acc = len * PRIME64_1
|
|
136
|
+
if len > 32
|
|
137
|
+
if len > 64
|
|
138
|
+
if len > 96
|
|
139
|
+
acc += mix16b(bytes, 48, 96)
|
|
140
|
+
acc += mix16b(bytes, len - 64, 112)
|
|
141
|
+
end
|
|
142
|
+
acc += mix16b(bytes, 32, 64)
|
|
143
|
+
acc += mix16b(bytes, len - 48, 80)
|
|
144
|
+
end
|
|
145
|
+
acc += mix16b(bytes, 16, 32)
|
|
146
|
+
acc += mix16b(bytes, len - 32, 48)
|
|
147
|
+
end
|
|
148
|
+
acc += mix16b(bytes, 0, 0)
|
|
149
|
+
acc += mix16b(bytes, len - 16, 16)
|
|
150
|
+
xxh3_avalanche(acc & MASK64)
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def len_129to240(bytes, len)
|
|
154
|
+
acc = len * PRIME64_1
|
|
155
|
+
nb_rounds = len / 16
|
|
156
|
+
8.times { |i| acc += mix16b(bytes, 16 * i, 16 * i) }
|
|
157
|
+
acc_end = mix16b(bytes, len - 16, SECRET_SIZE_MIN - MIDSIZE_LASTOFFSET)
|
|
158
|
+
acc = xxh3_avalanche(acc & MASK64)
|
|
159
|
+
(8...nb_rounds).each do |i|
|
|
160
|
+
acc_end += mix16b(bytes, 16 * i, (16 * (i - 8)) + MIDSIZE_STARTOFFSET)
|
|
161
|
+
end
|
|
162
|
+
xxh3_avalanche((acc + acc_end) & MASK64)
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
# --- long keys: len > 240 (striped accumulate + scramble, then merge) ---
|
|
166
|
+
|
|
167
|
+
def hash_long(bytes, len)
|
|
168
|
+
acc = INIT_ACC.dup
|
|
169
|
+
secret_size = SECRET.bytesize
|
|
170
|
+
nb_stripes_per_block = (secret_size - STRIPE_LEN) / SECRET_CONSUME_RATE
|
|
171
|
+
block_len = STRIPE_LEN * nb_stripes_per_block
|
|
172
|
+
nb_blocks = (len - 1) / block_len
|
|
173
|
+
|
|
174
|
+
nb_blocks.times do |n|
|
|
175
|
+
accumulate_stripes(acc, bytes, n * block_len, nb_stripes_per_block)
|
|
176
|
+
scramble(acc, secret_size - STRIPE_LEN)
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
last_off = nb_blocks * block_len
|
|
180
|
+
accumulate_stripes(acc, bytes, last_off, (len - 1 - last_off) / STRIPE_LEN)
|
|
181
|
+
accumulate_512(acc, bytes, len - STRIPE_LEN, secret_size - STRIPE_LEN - SECRET_LASTACC_START)
|
|
182
|
+
|
|
183
|
+
merge_accs(acc, len * PRIME64_1)
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def accumulate_stripes(acc, bytes, base_off, nb_stripes)
|
|
187
|
+
nb_stripes.times do |s|
|
|
188
|
+
accumulate_512(acc, bytes, base_off + (s * STRIPE_LEN), s * SECRET_CONSUME_RATE)
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
# XXH3_accumulate_512_scalar: each 64-byte stripe folds into the 8-lane accumulator — the
|
|
193
|
+
# data value is added to the swapped adjacent lane, and the secret-keyed value contributes a
|
|
194
|
+
# 32x32->64 product to its own lane.
|
|
195
|
+
def accumulate_512(acc, bytes, in_off, sec_off)
|
|
196
|
+
ACC_NB.times do |i|
|
|
197
|
+
data_val = u64(bytes, in_off + (8 * i))
|
|
198
|
+
data_key = data_val ^ u64(SECRET, sec_off + (8 * i))
|
|
199
|
+
acc[i ^ 1] = (acc[i ^ 1] + data_val) & MASK64
|
|
200
|
+
acc[i] = (acc[i] + ((data_key & MASK32) * (data_key >> 32))) & MASK64
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
# XXH3_scrambleAcc_scalar
|
|
205
|
+
def scramble(acc, sec_off)
|
|
206
|
+
ACC_NB.times do |i|
|
|
207
|
+
acc[i] = ((acc[i] ^ (acc[i] >> 47) ^ u64(SECRET, sec_off + (8 * i))) * PRIME32_1) & MASK64
|
|
208
|
+
end
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
# XXH3_mergeAccs over the default secret, at SECRET_MERGEACCS_START.
|
|
212
|
+
def merge_accs(acc, start)
|
|
213
|
+
result = start
|
|
214
|
+
4.times do |i|
|
|
215
|
+
result += mul128_fold64(acc[2 * i] ^ u64(SECRET, SECRET_MERGEACCS_START + (16 * i)),
|
|
216
|
+
acc[(2 * i) + 1] ^ u64(SECRET, SECRET_MERGEACCS_START + (16 * i) + 8))
|
|
217
|
+
end
|
|
218
|
+
xxh3_avalanche(result & MASK64)
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
# --- primitives ---
|
|
222
|
+
|
|
223
|
+
def u32(bytes, off) = bytes.unpack1("L<", offset: off)
|
|
224
|
+
|
|
225
|
+
def u64(bytes, off) = bytes.unpack1("Q<", offset: off)
|
|
226
|
+
|
|
227
|
+
def swap64(value) = [value].pack("Q>").unpack1("Q<")
|
|
228
|
+
|
|
229
|
+
def rotl64(value, shift) = ((value << shift) | (value >> (64 - shift))) & MASK64
|
|
230
|
+
|
|
231
|
+
def mul128_fold64(lhs, rhs)
|
|
232
|
+
product = lhs * rhs
|
|
233
|
+
(product & MASK64) ^ (product >> 64)
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
# XXH3_avalanche — the fast finalizer used when the input is already partially mixed.
|
|
237
|
+
def xxh3_avalanche(hash)
|
|
238
|
+
hash = (hash ^ (hash >> 37)) & MASK64
|
|
239
|
+
hash = (hash * PRIME_MX1) & MASK64
|
|
240
|
+
hash ^ (hash >> 32)
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
# XXH64_avalanche — the stronger finalizer for the shortest keys.
|
|
244
|
+
def xxh64_avalanche(hash)
|
|
245
|
+
hash ^= hash >> 33
|
|
246
|
+
hash = (hash * PRIME64_2) & MASK64
|
|
247
|
+
hash ^= hash >> 29
|
|
248
|
+
hash = (hash * PRIME64_3) & MASK64
|
|
249
|
+
hash ^ (hash >> 32)
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
# XXH3_rrmxmx — the len 4-8 finalizer (Pelle Evensen's mix).
|
|
253
|
+
def rrmxmx(hash, len)
|
|
254
|
+
hash = (hash ^ rotl64(hash, 49) ^ rotl64(hash, 24)) & MASK64
|
|
255
|
+
hash = (hash * PRIME_MX2) & MASK64
|
|
256
|
+
hash ^= (hash >> 35) + len
|
|
257
|
+
hash = (hash * PRIME_MX2) & MASK64
|
|
258
|
+
hash ^ (hash >> 28)
|
|
259
|
+
end
|
|
260
|
+
end
|
|
261
|
+
# rubocop:enable Naming/VariableNumber
|
|
262
|
+
end
|
|
263
|
+
end
|
|
264
|
+
end
|