rigortype 0.2.7 → 0.2.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/docs/manual/04-diagnostics.md +7 -4
- data/docs/manual/06-baseline.md +5 -2
- data/docs/manual/15-type-protection-coverage.md +6 -4
- data/lib/rigor/analysis/baseline.rb +56 -96
- data/lib/rigor/analysis/buffer_binding.rb +13 -20
- data/lib/rigor/analysis/check_rules/always_truthy_condition_collector.rb +29 -48
- data/lib/rigor/analysis/check_rules/dead_assignment_collector.rb +35 -54
- data/lib/rigor/analysis/check_rules/ivar_write_collector.rb +23 -37
- data/lib/rigor/analysis/check_rules/main_pass_collector.rb +16 -23
- data/lib/rigor/analysis/check_rules/rule_walk.rb +48 -71
- data/lib/rigor/analysis/check_rules/self_closedness_scanner.rb +19 -28
- data/lib/rigor/analysis/check_rules/unreachable_clause_collector.rb +48 -67
- data/lib/rigor/analysis/check_rules.rb +174 -274
- data/lib/rigor/analysis/dependency_recorder.rb +26 -38
- data/lib/rigor/analysis/dependency_source_inference/boundary_cross_reporter.rb +13 -25
- data/lib/rigor/analysis/dependency_source_inference/builder.rb +17 -30
- data/lib/rigor/analysis/dependency_source_inference/gem_resolver.rb +15 -26
- data/lib/rigor/analysis/dependency_source_inference/index.rb +45 -76
- data/lib/rigor/analysis/dependency_source_inference/return_type_heuristic.rb +23 -40
- data/lib/rigor/analysis/dependency_source_inference/walker.rb +50 -83
- data/lib/rigor/analysis/dependency_source_inference.rb +6 -10
- data/lib/rigor/analysis/diagnostic.rb +48 -75
- data/lib/rigor/analysis/erb_template_detector.rb +13 -18
- data/lib/rigor/analysis/fact_store.rb +12 -22
- data/lib/rigor/analysis/incremental.rb +47 -63
- data/lib/rigor/analysis/incremental_session.rb +74 -100
- data/lib/rigor/analysis/project_scan.rb +12 -23
- data/lib/rigor/analysis/result.rb +3 -5
- data/lib/rigor/analysis/rule_catalog.rb +67 -95
- data/lib/rigor/analysis/run_stats.rb +38 -61
- data/lib/rigor/analysis/runner/diagnostic_aggregator.rb +101 -160
- data/lib/rigor/analysis/runner/pool_coordinator.rb +121 -188
- data/lib/rigor/analysis/runner/project_pre_passes.rb +62 -96
- data/lib/rigor/analysis/runner/run_snapshots.rb +12 -18
- data/lib/rigor/analysis/runner.rb +220 -333
- data/lib/rigor/analysis/self_call_resolution_recorder.rb +30 -43
- data/lib/rigor/analysis/worker_session.rb +64 -102
- data/lib/rigor/ast/type_node.rb +6 -8
- data/lib/rigor/ast.rb +6 -10
- data/lib/rigor/bleeding_edge.rb +27 -35
- data/lib/rigor/builtins/hkt_builtins.rb +7 -14
- data/lib/rigor/builtins/imported_refinements.rb +106 -149
- data/lib/rigor/builtins/predefined_constant_refinements.rb +51 -65
- data/lib/rigor/builtins/regex_refinement.rb +32 -43
- data/lib/rigor/builtins/static_return_refinements.rb +57 -81
- data/lib/rigor/cache/descriptor.rb +58 -94
- data/lib/rigor/cache/incremental_snapshot.rb +32 -48
- data/lib/rigor/cache/rbs_cache_producer.rb +10 -15
- data/lib/rigor/cache/rbs_class_ancestor_table.rb +10 -16
- data/lib/rigor/cache/rbs_class_type_param_names.rb +10 -16
- data/lib/rigor/cache/rbs_constant_table.rb +8 -13
- data/lib/rigor/cache/rbs_descriptor.rb +8 -13
- data/lib/rigor/cache/rbs_environment.rb +11 -19
- data/lib/rigor/cache/rbs_environment_marshal_patch.rb +11 -19
- data/lib/rigor/cache/rbs_known_class_names.rb +8 -12
- data/lib/rigor/cache/store.rb +96 -151
- data/lib/rigor/cli/annotate_command.rb +51 -88
- data/lib/rigor/cli/baseline_command.rb +10 -17
- data/lib/rigor/cli/check_command.rb +121 -199
- data/lib/rigor/cli/check_runner_factory.rb +8 -14
- data/lib/rigor/cli/ci_detector.rb +9 -14
- data/lib/rigor/cli/command.rb +8 -14
- data/lib/rigor/cli/coverage_command.rb +19 -26
- data/lib/rigor/cli/coverage_mutation.rb +14 -19
- data/lib/rigor/cli/coverage_report.rb +0 -2
- data/lib/rigor/cli/coverage_scan.rb +7 -11
- data/lib/rigor/cli/diagnostic_formats.rb +43 -62
- data/lib/rigor/cli/diff_command.rb +10 -20
- data/lib/rigor/cli/docs_command.rb +26 -40
- data/lib/rigor/cli/doctor_command.rb +8 -9
- data/lib/rigor/cli/explain_command.rb +4 -7
- data/lib/rigor/cli/fused_protection_renderer.rb +4 -5
- data/lib/rigor/cli/fused_protection_report.rb +6 -8
- data/lib/rigor/cli/lsp_command.rb +11 -19
- data/lib/rigor/cli/mcp_command.rb +4 -6
- data/lib/rigor/cli/mutation_protection_renderer.rb +3 -4
- data/lib/rigor/cli/mutation_protection_report.rb +6 -9
- data/lib/rigor/cli/options.rb +11 -19
- data/lib/rigor/cli/plugin_command.rb +18 -30
- data/lib/rigor/cli/plugins_command.rb +29 -51
- data/lib/rigor/cli/plugins_renderer.rb +12 -20
- data/lib/rigor/cli/prism_colorizer.rb +13 -19
- data/lib/rigor/cli/protection_renderer.rb +5 -7
- data/lib/rigor/cli/protection_report.rb +27 -17
- data/lib/rigor/cli/renderable.rb +4 -6
- data/lib/rigor/cli/show_bleedingedge_command.rb +5 -8
- data/lib/rigor/cli/sig_gen_command.rb +14 -26
- data/lib/rigor/cli/skill_command.rb +30 -47
- data/lib/rigor/cli/skill_describe.rb +40 -64
- data/lib/rigor/cli/trace_command.rb +9 -16
- data/lib/rigor/cli/trace_renderer.rb +35 -51
- data/lib/rigor/cli/triage_command.rb +6 -10
- data/lib/rigor/cli/triage_renderer.rb +1 -2
- data/lib/rigor/cli/type_of_command.rb +14 -23
- data/lib/rigor/cli/type_of_renderer.rb +3 -5
- data/lib/rigor/cli/type_scan_command.rb +6 -10
- data/lib/rigor/cli/type_scan_renderer.rb +3 -5
- data/lib/rigor/cli/type_scan_report.rb +2 -3
- data/lib/rigor/cli/upgrade_command.rb +2 -3
- data/lib/rigor/cli.rb +16 -28
- data/lib/rigor/config_audit.rb +35 -44
- data/lib/rigor/configuration/dependencies.rb +41 -70
- data/lib/rigor/configuration/severity_profile.rb +28 -42
- data/lib/rigor/configuration.rb +150 -241
- data/lib/rigor/environment/bundle_sig_discovery.rb +74 -118
- data/lib/rigor/environment/class_registry.rb +19 -26
- data/lib/rigor/environment/constant_type_cache_holder.rb +14 -21
- data/lib/rigor/environment/hkt_registry_holder.rb +6 -12
- data/lib/rigor/environment/lockfile_resolver.rb +31 -47
- data/lib/rigor/environment/rbs_collection_discovery.rb +39 -63
- data/lib/rigor/environment/rbs_coverage_report.rb +24 -42
- data/lib/rigor/environment/rbs_loader.rb +420 -518
- data/lib/rigor/environment/reflection.rb +28 -53
- data/lib/rigor/environment/reporters.rb +13 -24
- data/lib/rigor/environment.rb +176 -291
- data/lib/rigor/flow_contribution/conflict.rb +16 -27
- data/lib/rigor/flow_contribution/element.rb +7 -12
- data/lib/rigor/flow_contribution/fact.rb +33 -57
- data/lib/rigor/flow_contribution/merge_result.rb +6 -9
- data/lib/rigor/flow_contribution/merger.rb +32 -47
- data/lib/rigor/flow_contribution.rb +37 -55
- data/lib/rigor/inference/acceptance.rb +133 -219
- data/lib/rigor/inference/block_parameter_binder.rb +52 -82
- data/lib/rigor/inference/body_fixpoint.rb +22 -30
- data/lib/rigor/inference/budget_trace.rb +43 -63
- data/lib/rigor/inference/builtins/array_catalog.rb +4 -6
- data/lib/rigor/inference/builtins/comparable_catalog.rb +4 -6
- data/lib/rigor/inference/builtins/complex_catalog.rb +13 -19
- data/lib/rigor/inference/builtins/date_catalog.rb +38 -67
- data/lib/rigor/inference/builtins/encoding_catalog.rb +22 -36
- data/lib/rigor/inference/builtins/enumerable_catalog.rb +4 -6
- data/lib/rigor/inference/builtins/exception_catalog.rb +38 -57
- data/lib/rigor/inference/builtins/hash_catalog.rb +9 -14
- data/lib/rigor/inference/builtins/method_catalog.rb +29 -48
- data/lib/rigor/inference/builtins/numeric_catalog.rb +13 -18
- data/lib/rigor/inference/builtins/pathname_catalog.rb +8 -13
- data/lib/rigor/inference/builtins/proc_catalog.rb +38 -62
- data/lib/rigor/inference/builtins/random_catalog.rb +21 -32
- data/lib/rigor/inference/builtins/range_catalog.rb +12 -21
- data/lib/rigor/inference/builtins/rational_catalog.rb +9 -15
- data/lib/rigor/inference/builtins/re_catalog.rb +29 -48
- data/lib/rigor/inference/builtins/set_catalog.rb +18 -27
- data/lib/rigor/inference/builtins/string_catalog.rb +12 -19
- data/lib/rigor/inference/builtins/struct_catalog.rb +18 -30
- data/lib/rigor/inference/builtins/time_catalog.rb +28 -44
- data/lib/rigor/inference/closure_escape_analyzer.rb +44 -67
- data/lib/rigor/inference/coverage_scanner.rb +13 -18
- data/lib/rigor/inference/def_return_typer.rb +8 -14
- data/lib/rigor/inference/dynamic_origin.rb +23 -20
- data/lib/rigor/inference/expression_typer.rb +774 -1152
- data/lib/rigor/inference/fallback.rb +8 -12
- data/lib/rigor/inference/fallback_tracer.rb +4 -10
- data/lib/rigor/inference/flow_tracer.rb +25 -36
- data/lib/rigor/inference/hkt_body.rb +45 -68
- data/lib/rigor/inference/hkt_body_parser.rb +33 -52
- data/lib/rigor/inference/hkt_reducer.rb +38 -59
- data/lib/rigor/inference/hkt_registry.rb +50 -76
- data/lib/rigor/inference/indexed_narrowing.rb +55 -81
- data/lib/rigor/inference/macro_block_self_type.rb +21 -34
- data/lib/rigor/inference/method_dispatcher/array_to_h_folding.rb +11 -18
- data/lib/rigor/inference/method_dispatcher/block_folding.rb +49 -83
- data/lib/rigor/inference/method_dispatcher/call_context.rb +16 -23
- data/lib/rigor/inference/method_dispatcher/cgi_folding.rb +13 -22
- data/lib/rigor/inference/method_dispatcher/constant_folding.rb +307 -454
- data/lib/rigor/inference/method_dispatcher/data_folding.rb +24 -34
- data/lib/rigor/inference/method_dispatcher/file_folding.rb +22 -37
- data/lib/rigor/inference/method_dispatcher/iterator_dispatch.rb +52 -81
- data/lib/rigor/inference/method_dispatcher/kernel_dispatch.rb +51 -78
- data/lib/rigor/inference/method_dispatcher/literal_string_folding.rb +60 -97
- data/lib/rigor/inference/method_dispatcher/math_folding.rb +23 -34
- data/lib/rigor/inference/method_dispatcher/member_shape_projection.rb +18 -26
- data/lib/rigor/inference/method_dispatcher/method_folding.rb +37 -71
- data/lib/rigor/inference/method_dispatcher/overload_selector.rb +114 -182
- data/lib/rigor/inference/method_dispatcher/rbs_dispatch.rb +122 -193
- data/lib/rigor/inference/method_dispatcher/receiver_affinity.rb +15 -24
- data/lib/rigor/inference/method_dispatcher/reduce_folding.rb +64 -93
- data/lib/rigor/inference/method_dispatcher/regexp_folding.rb +31 -45
- data/lib/rigor/inference/method_dispatcher/set_folding.rb +6 -9
- data/lib/rigor/inference/method_dispatcher/shape_dispatch.rb +356 -511
- data/lib/rigor/inference/method_dispatcher/shellwords_folding.rb +22 -32
- data/lib/rigor/inference/method_dispatcher/singleton_folding.rb +15 -21
- data/lib/rigor/inference/method_dispatcher/struct_folding.rb +66 -82
- data/lib/rigor/inference/method_dispatcher/time_folding.rb +10 -15
- data/lib/rigor/inference/method_dispatcher/uri_folding.rb +9 -13
- data/lib/rigor/inference/method_dispatcher.rb +378 -524
- data/lib/rigor/inference/method_parameter_binder.rb +81 -114
- data/lib/rigor/inference/multi_target_binder.rb +51 -68
- data/lib/rigor/inference/mutation_widening.rb +115 -158
- data/lib/rigor/inference/narrowing.rb +509 -727
- data/lib/rigor/inference/origin_lookup.rb +38 -0
- data/lib/rigor/inference/parameter_inference_collector.rb +100 -100
- data/lib/rigor/inference/precision_scanner.rb +26 -35
- data/lib/rigor/inference/project_patched_methods.rb +20 -32
- data/lib/rigor/inference/project_patched_scanner.rb +23 -37
- data/lib/rigor/inference/protection_scanner.rb +16 -18
- data/lib/rigor/inference/rbs_type_translator.rb +49 -66
- data/lib/rigor/inference/scope_indexer.rb +473 -817
- data/lib/rigor/inference/statement_evaluator.rb +706 -1111
- data/lib/rigor/inference/struct_fold_safety.rb +34 -48
- data/lib/rigor/inference/synthetic_method.rb +9 -16
- data/lib/rigor/inference/synthetic_method_index.rb +20 -35
- data/lib/rigor/inference/synthetic_method_scanner.rb +63 -103
- data/lib/rigor/language_server/buffer_resolution.rb +6 -9
- data/lib/rigor/language_server/buffer_table.rb +11 -18
- data/lib/rigor/language_server/completion_provider.rb +69 -116
- data/lib/rigor/language_server/debouncer.rb +16 -25
- data/lib/rigor/language_server/diagnostic_publisher.rb +26 -40
- data/lib/rigor/language_server/document_symbol_provider.rb +14 -19
- data/lib/rigor/language_server/folding_range_provider.rb +11 -19
- data/lib/rigor/language_server/hover_provider.rb +8 -11
- data/lib/rigor/language_server/hover_renderer.rb +56 -93
- data/lib/rigor/language_server/loop.rb +14 -19
- data/lib/rigor/language_server/project_context.rb +46 -74
- data/lib/rigor/language_server/selection_range_provider.rb +9 -12
- data/lib/rigor/language_server/server.rb +55 -83
- data/lib/rigor/language_server/signature_help_provider.rb +29 -46
- data/lib/rigor/language_server/synchronized_writer.rb +4 -7
- data/lib/rigor/language_server/uri.rb +8 -13
- data/lib/rigor/language_server.rb +4 -6
- data/lib/rigor/mcp/loop.rb +2 -3
- data/lib/rigor/mcp/server.rb +4 -7
- data/lib/rigor/mcp.rb +3 -6
- data/lib/rigor/plugin/access_denied_error.rb +5 -8
- data/lib/rigor/plugin/additional_initializer.rb +21 -31
- data/lib/rigor/plugin/base.rb +335 -518
- data/lib/rigor/plugin/blueprint.rb +14 -23
- data/lib/rigor/plugin/box.rb +18 -29
- data/lib/rigor/plugin/fact_store.rb +16 -26
- data/lib/rigor/plugin/inflector.rb +37 -53
- data/lib/rigor/plugin/io_boundary.rb +33 -56
- data/lib/rigor/plugin/isolation.rb +42 -55
- data/lib/rigor/plugin/load_error.rb +10 -15
- data/lib/rigor/plugin/loader.rb +30 -49
- data/lib/rigor/plugin/macro/block_as_method.rb +20 -32
- data/lib/rigor/plugin/macro/heredoc_template.rb +35 -58
- data/lib/rigor/plugin/macro/nested_class_template.rb +22 -36
- data/lib/rigor/plugin/macro/trait_registry.rb +34 -51
- data/lib/rigor/plugin/macro.rb +10 -15
- data/lib/rigor/plugin/manifest.rb +85 -144
- data/lib/rigor/plugin/node_context.rb +14 -22
- data/lib/rigor/plugin/node_rule_walk.rb +49 -74
- data/lib/rigor/plugin/protocol_contract.rb +25 -39
- data/lib/rigor/plugin/registry.rb +132 -205
- data/lib/rigor/plugin/services.rb +21 -33
- data/lib/rigor/plugin/source_rbs_synthesis_reporter.rb +11 -19
- data/lib/rigor/plugin/trust_policy.rb +24 -38
- data/lib/rigor/plugin/type_node_resolver.rb +15 -24
- data/lib/rigor/protection/diagnostic_oracle.rb +11 -13
- data/lib/rigor/protection/mutation_scanner.rb +27 -35
- data/lib/rigor/protection/mutator.rb +50 -70
- data/lib/rigor/protection/test_suite_oracle.rb +20 -27
- data/lib/rigor/rbs_extended/conformance_checker.rb +48 -68
- data/lib/rigor/rbs_extended/hkt_directives.rb +28 -54
- data/lib/rigor/rbs_extended/reporter.rb +24 -40
- data/lib/rigor/rbs_extended.rb +107 -197
- data/lib/rigor/reflection.rb +68 -86
- data/lib/rigor/scope/discovery_index.rb +14 -19
- data/lib/rigor/scope.rb +255 -310
- data/lib/rigor/sig_gen/classification.rb +6 -10
- data/lib/rigor/sig_gen/generator.rb +197 -323
- data/lib/rigor/sig_gen/layout_index.rb +12 -20
- data/lib/rigor/sig_gen/method_candidate.rb +12 -17
- data/lib/rigor/sig_gen/observation_collector.rb +38 -70
- data/lib/rigor/sig_gen/observed_call.rb +13 -23
- data/lib/rigor/sig_gen/path_mapper.rb +17 -29
- data/lib/rigor/sig_gen/renderer.rb +7 -13
- data/lib/rigor/sig_gen/type_elaborator.rb +15 -28
- data/lib/rigor/sig_gen/write_result.rb +8 -16
- data/lib/rigor/sig_gen/writer.rb +95 -174
- data/lib/rigor/sig_gen.rb +3 -6
- data/lib/rigor/signature_path_audit.rb +24 -30
- data/lib/rigor/source/constant_path.rb +10 -14
- data/lib/rigor/source/literals.rb +31 -45
- data/lib/rigor/source/node_locator.rb +9 -11
- data/lib/rigor/source/node_walker.rb +9 -13
- data/lib/rigor/source.rb +3 -4
- data/lib/rigor/testing.rb +16 -20
- data/lib/rigor/triage/catalogue.rb +38 -62
- data/lib/rigor/triage.rb +31 -52
- data/lib/rigor/trinary.rb +9 -13
- data/lib/rigor/type/acceptance_router.rb +4 -6
- data/lib/rigor/type/accepts_result.rb +10 -14
- data/lib/rigor/type/app.rb +19 -27
- data/lib/rigor/type/bot.rb +4 -6
- data/lib/rigor/type/bound_method.rb +10 -15
- data/lib/rigor/type/combinator.rb +165 -257
- data/lib/rigor/type/constant.rb +23 -34
- data/lib/rigor/type/data_class.rb +10 -15
- data/lib/rigor/type/data_instance.rb +14 -20
- data/lib/rigor/type/difference.rb +21 -32
- data/lib/rigor/type/dynamic.rb +3 -5
- data/lib/rigor/type/hash_shape.rb +32 -18
- data/lib/rigor/type/integer_range.rb +11 -16
- data/lib/rigor/type/intersection.rb +27 -42
- data/lib/rigor/type/nominal.rb +10 -15
- data/lib/rigor/type/plain_lattice.rb +9 -13
- data/lib/rigor/type/refined.rb +67 -114
- data/lib/rigor/type/singleton.rb +4 -6
- data/lib/rigor/type/struct_class.rb +11 -16
- data/lib/rigor/type/struct_instance.rb +15 -21
- data/lib/rigor/type/tuple.rb +14 -19
- data/lib/rigor/type/union.rb +30 -42
- data/lib/rigor/type_node/generic.rb +14 -26
- data/lib/rigor/type_node/identifier.rb +12 -19
- data/lib/rigor/type_node.rb +3 -12
- data/lib/rigor/value_semantics.rb +16 -21
- data/lib/rigor/version.rb +1 -1
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/analyzer.rb +18 -30
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_discoverer.rb +16 -29
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_index.rb +12 -23
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable.rb +22 -39
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/analyzer.rb +26 -46
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_discoverer.rb +51 -87
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_index.rb +10 -17
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer.rb +26 -39
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/analyzer.rb +118 -176
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_discoverer.rb +30 -51
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_index.rb +57 -92
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack.rb +71 -108
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/analyzer.rb +13 -22
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_discoverer.rb +15 -25
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_index.rb +8 -13
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob.rb +16 -24
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/analyzer.rb +30 -47
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_discoverer.rb +79 -129
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_index.rb +36 -57
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_parser.rb +27 -41
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_table.rb +16 -24
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord.rb +148 -235
- data/plugins/rigor-activerecord/lib/rigor-activerecord.rb +3 -5
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/analyzer.rb +8 -14
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/attachment_discoverer.rb +9 -15
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/attachment_index.rb +4 -7
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage.rb +23 -41
- data/plugins/rigor-activestorage/lib/rigor-activestorage.rb +3 -5
- data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext.rb +6 -10
- data/plugins/rigor-activesupport-core-ext/lib/rigor-activesupport-core-ext.rb +8 -11
- data/plugins/rigor-devise/lib/rigor/plugin/devise.rb +30 -45
- data/plugins/rigor-devise/lib/rigor-devise.rb +3 -5
- data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema/schema_scanner.rb +43 -69
- data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema.rb +26 -35
- data/plugins/rigor-dry-schema/lib/rigor-dry-schema.rb +3 -5
- data/plugins/rigor-dry-struct/lib/rigor/plugin/dry_struct.rb +30 -47
- data/plugins/rigor-dry-struct/lib/rigor-dry-struct.rb +3 -5
- data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types/alias_scanner.rb +67 -113
- data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types.rb +29 -46
- data/plugins/rigor-dry-types/lib/rigor-dry-types.rb +3 -5
- data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation/contract_scanner.rb +13 -20
- data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation.rb +14 -23
- data/plugins/rigor-dry-validation/lib/rigor-dry-validation.rb +2 -3
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/analyzer.rb +22 -37
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_discoverer.rb +28 -46
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_index.rb +13 -17
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot.rb +30 -47
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql/type_scanner.rb +52 -80
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql.rb +21 -31
- data/plugins/rigor-graphql/lib/rigor-graphql.rb +3 -5
- data/plugins/rigor-hanami/lib/rigor/plugin/hanami/action_checker.rb +11 -17
- data/plugins/rigor-hanami/lib/rigor/plugin/hanami.rb +20 -34
- data/plugins/rigor-mangrove/lib/rigor/plugin/mangrove.rb +45 -75
- data/plugins/rigor-minitest/lib/rigor/plugin/minitest/assertion_analyzer.rb +22 -36
- data/plugins/rigor-minitest/lib/rigor/plugin/minitest.rb +22 -41
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/analyzer.rb +17 -32
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_discoverer.rb +6 -12
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_index.rb +4 -8
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit.rb +17 -32
- data/plugins/rigor-rails/lib/rigor-rails.rb +11 -18
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/analyzer.rb +58 -92
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_index.rb +20 -34
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_loader.rb +20 -31
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n.rb +49 -82
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/analyzer.rb +55 -92
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/devise_routes.rb +51 -90
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/doorkeeper_routes.rb +17 -30
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_discoverer.rb +38 -70
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_table.rb +42 -74
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/routes_parser.rb +280 -497
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes.rb +54 -89
- data/plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline.rb +32 -54
- data/plugins/rigor-rbs-inline/lib/rigor-rbs-inline.rb +8 -13
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/analyzer.rb +9 -16
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_scope_index.rb +24 -39
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_type_resolver.rb +13 -22
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/matcher_analyzer.rb +34 -56
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/scope_walker.rb +22 -42
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec.rb +43 -75
- data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails/have_http_status_analyzer.rb +27 -39
- data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails/http_status_codes.rb +14 -19
- data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails.rb +20 -34
- data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers/analyzer.rb +28 -47
- data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers.rb +21 -37
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/analyzer.rb +13 -22
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_discoverer.rb +18 -31
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_index.rb +6 -10
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq.rb +14 -29
- data/plugins/rigor-sinatra/lib/rigor/plugin/sinatra.rb +23 -41
- data/plugins/rigor-sinatra/lib/rigor-sinatra.rb +3 -5
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/absurd_recognizer.rb +23 -38
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/assertion_recognizer.rb +57 -96
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog.rb +22 -35
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog_walker.rb +41 -69
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/method_signature.rb +6 -10
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sig_parser.rb +24 -41
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sigil_detector.rb +29 -50
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/type_translator.rb +55 -88
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet.rb +159 -262
- data/plugins/rigor-statesman/lib/rigor/plugin/statesman.rb +21 -29
- data/plugins/rigor-statesman/lib/rigor-statesman.rb +3 -5
- data/plugins/rigor-typescript-utility-types/lib/rigor/plugin/typescript_utility_types.rb +23 -37
- data/plugins/rigor-typescript-utility-types/lib/rigor-typescript-utility-types.rb +4 -6
- data/sig/rigor/scope.rbs +6 -0
- metadata +2 -1
|
@@ -4,33 +4,25 @@ require_relative "command"
|
|
|
4
4
|
|
|
5
5
|
module Rigor
|
|
6
6
|
class CLI
|
|
7
|
-
# `rigor docs` — serve the documentation bundled with the
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
# rigor.typedduck.fail/llms.txt; the gem ships `docs/install.md`,
|
|
13
|
-
# `docs/llms.txt`, and the full user-facing **manual** and
|
|
14
|
-
# **handbook** (the drive-Rigor chapters — the contributor-facing
|
|
15
|
-
# ADR / spec / notes corpus stays web-only).
|
|
7
|
+
# `rigor docs` — serve the documentation bundled with the `rigortype` gem OFFLINE (ADR-74). The skills (`rigor skill
|
|
8
|
+
# <name>`) already ride in the gem; this is the doc twin, so once Rigor is installed an agent can read the guidance
|
|
9
|
+
# the SKILL-driven UX routes to without the network. The canonical web copy is rigor.typedduck.fail/llms.txt; the
|
|
10
|
+
# gem ships `docs/install.md`, `docs/llms.txt`, and the full user-facing **manual** and **handbook** (the
|
|
11
|
+
# drive-Rigor chapters — the contributor-facing ADR / spec / notes corpus stays web-only).
|
|
16
12
|
#
|
|
17
|
-
# Grammar (mirrors `rigor skill`): the positional slot is always a
|
|
18
|
-
#
|
|
19
|
-
# or `path` can never be shadowed by a verb.
|
|
13
|
+
# Grammar (mirrors `rigor skill`): the positional slot is always a doc *name*; alternative outputs are flags, so a
|
|
14
|
+
# page named `list` or `path` can never be shadowed by a verb.
|
|
20
15
|
#
|
|
21
16
|
# - `rigor docs` — print the bundled `llms.txt` index.
|
|
22
17
|
# - `rigor docs <name>` — print a doc page to stdout.
|
|
23
18
|
# - `rigor docs --path <name>` — one-line absolute path, for a Read tool.
|
|
24
19
|
# - `rigor docs --list [<cat>]` — table of name + path (optionally one category).
|
|
25
20
|
#
|
|
26
|
-
# `<name>` resolves a category-qualified path (`handbook/03-narrowing`),
|
|
27
|
-
#
|
|
28
|
-
# when it is unique across categories).
|
|
21
|
+
# `<name>` resolves a category-qualified path (`handbook/03-narrowing`), a prefixed basename (`03-narrowing`), or a
|
|
22
|
+
# short name (`narrowing`, when it is unique across categories).
|
|
29
23
|
#
|
|
30
|
-
# The pre-v0.3.0 verb spellings `rigor docs list` / `rigor docs path
|
|
31
|
-
#
|
|
32
|
-
# removed in v0.3.0 (see docs/ROADMAP.md § "Scheduled CLI
|
|
33
|
-
# deprecations").
|
|
24
|
+
# The pre-v0.3.0 verb spellings `rigor docs list` / `rigor docs path <name>` still work but emit a stderr
|
|
25
|
+
# deprecation notice; they are removed in v0.3.0 (see docs/ROADMAP.md § "Scheduled CLI deprecations").
|
|
34
26
|
class DocsCommand < Command
|
|
35
27
|
USAGE = <<~USAGE
|
|
36
28
|
Usage: rigor docs [<name>] [--path <name>] [--list [<category>]]
|
|
@@ -60,16 +52,14 @@ module Rigor
|
|
|
60
52
|
rigor docs path <name> -> rigor docs --path <name>
|
|
61
53
|
USAGE
|
|
62
54
|
|
|
63
|
-
# The bundled docs live at `<gem_root>/docs/`. From
|
|
64
|
-
# `lib/rigor/cli/docs_command.rb` that is three directories up.
|
|
55
|
+
# The bundled docs live at `<gem_root>/docs/`. From `lib/rigor/cli/docs_command.rb` that is three directories up.
|
|
65
56
|
DOCS_ROOT = File.expand_path("../../../docs", __dir__)
|
|
66
57
|
MANUAL_ROOT = File.join(DOCS_ROOT, "manual")
|
|
67
58
|
HANDBOOK_ROOT = File.join(DOCS_ROOT, "handbook")
|
|
68
59
|
LLMS_INDEX = File.join(DOCS_ROOT, "llms.txt")
|
|
69
60
|
|
|
70
|
-
# The verb subcommands the flags superseded keep working with a
|
|
71
|
-
#
|
|
72
|
-
# to the canonical advice printed and the flag it rewrites to.
|
|
61
|
+
# The verb subcommands the flags superseded keep working with a stderr deprecation notice until this version drops
|
|
62
|
+
# them. Each maps to the canonical advice printed and the flag it rewrites to.
|
|
73
63
|
LEGACY_VERB_REMOVAL = "v0.3.0"
|
|
74
64
|
LEGACY_VERBS = {
|
|
75
65
|
"list" => { old: "list", advice: "--list", flag: "--list" },
|
|
@@ -102,8 +92,8 @@ module Rigor
|
|
|
102
92
|
|
|
103
93
|
private
|
|
104
94
|
|
|
105
|
-
# Translate a deprecated verb spelling into its flag form, warning
|
|
106
|
-
#
|
|
95
|
+
# Translate a deprecated verb spelling into its flag form, warning once on stderr, so the dispatch above only
|
|
96
|
+
# handles canonical forms.
|
|
107
97
|
def rewrite_legacy_verb!
|
|
108
98
|
spec = LEGACY_VERBS[@argv.first]
|
|
109
99
|
return unless spec
|
|
@@ -154,9 +144,8 @@ module Rigor
|
|
|
154
144
|
doc = resolve_doc(name)
|
|
155
145
|
return doc if doc.is_a?(Integer) # error status, already reported
|
|
156
146
|
|
|
157
|
-
# ASCII-only provenance header: the doc body is read with the
|
|
158
|
-
#
|
|
159
|
-
# would set the output buffer to UTF-8 and clash with the body.
|
|
147
|
+
# ASCII-only provenance header: the doc body is read with the external encoding (US-ASCII under a C locale), so
|
|
148
|
+
# a UTF-8 header would set the output buffer to UTF-8 and clash with the body.
|
|
160
149
|
@out.puts("<!-- rigor docs #{doc.fetch(:name)} (rigortype #{Rigor::VERSION}, offline) -->")
|
|
161
150
|
@out.puts
|
|
162
151
|
@out.write(File.read(doc.fetch(:path)))
|
|
@@ -173,9 +162,8 @@ module Rigor
|
|
|
173
162
|
0
|
|
174
163
|
end
|
|
175
164
|
|
|
176
|
-
# Resolve a query to a single doc. Exact relative-path and
|
|
177
|
-
#
|
|
178
|
-
# name is accepted only when one category owns it.
|
|
165
|
+
# Resolve a query to a single doc. Exact relative-path and prefixed-basename aliases are unique; a short
|
|
166
|
+
# (prefix-stripped) name is accepted only when one category owns it.
|
|
179
167
|
#
|
|
180
168
|
# @return [Hash, Integer] the doc entry, or an error exit status
|
|
181
169
|
# after the error has been written to `@err`.
|
|
@@ -193,10 +181,8 @@ module Rigor
|
|
|
193
181
|
end
|
|
194
182
|
end
|
|
195
183
|
|
|
196
|
-
# Every bundled doc, each carrying the aliases `rigor docs <name>`
|
|
197
|
-
#
|
|
198
|
-
# the docs root (category `guide`); the rest are manual / handbook
|
|
199
|
-
# chapters.
|
|
184
|
+
# Every bundled doc, each carrying the aliases `rigor docs <name>` accepts and the category used by `--list`.
|
|
185
|
+
# `install.md` sits at the docs root (category `guide`); the rest are manual / handbook chapters.
|
|
200
186
|
def discover_docs
|
|
201
187
|
paths = [File.join(DOCS_ROOT, "install.md")]
|
|
202
188
|
paths += Dir.glob(File.join(MANUAL_ROOT, "**", "*.md")) # Dir.glob is already sorted
|
|
@@ -215,11 +201,11 @@ module Rigor
|
|
|
215
201
|
relative: relative,
|
|
216
202
|
path: path,
|
|
217
203
|
category: category,
|
|
218
|
-
# Always-unique addresses: the `docs/`-relative path and the
|
|
219
|
-
#
|
|
204
|
+
# Always-unique addresses: the `docs/`-relative path and the prefixed basename. `handbook/03-narrowing` and
|
|
205
|
+
# `03-narrowing`.
|
|
220
206
|
exact_aliases: [relative, base].uniq,
|
|
221
|
-
# The prefix-stripped short name (`narrowing`); ambiguous when
|
|
222
|
-
#
|
|
207
|
+
# The prefix-stripped short name (`narrowing`); ambiguous when two categories carry the same chapter slug
|
|
208
|
+
# (`plugins`).
|
|
223
209
|
short_name: short
|
|
224
210
|
}
|
|
225
211
|
end
|
|
@@ -18,14 +18,13 @@ require_relative "options"
|
|
|
18
18
|
|
|
19
19
|
module Rigor
|
|
20
20
|
class CLI
|
|
21
|
-
# `rigor doctor` — classify existing project findings into setup-problem
|
|
22
|
-
#
|
|
21
|
+
# `rigor doctor` — classify existing project findings into setup-problem vs clean-run with a routed next action
|
|
22
|
+
# (ADR-77 WD1).
|
|
23
23
|
#
|
|
24
24
|
# It is a presentation/aggregation layer over data `rigor check` already
|
|
25
25
|
# produces — no new analysis pass and no new diagnostic rule. The
|
|
26
|
-
# command runs a scoped analysis to gather stats, audits the
|
|
27
|
-
#
|
|
28
|
-
# reports a small fixed set of checks with a hint for each failure.
|
|
26
|
+
# command runs a scoped analysis to gather stats, audits the configuration, validates plugins, and checks baseline
|
|
27
|
+
# drift, then reports a small fixed set of checks with a hint for each failure.
|
|
29
28
|
class DoctorCommand < Command # rubocop:disable Metrics/ClassLength
|
|
30
29
|
USAGE = "Usage: rigor doctor [options]"
|
|
31
30
|
|
|
@@ -100,8 +99,8 @@ module Rigor
|
|
|
100
99
|
end
|
|
101
100
|
|
|
102
101
|
# ------------------------------------------------------------------
|
|
103
|
-
# Individual checks — each returns an Array of finding Hashes.
|
|
104
|
-
#
|
|
102
|
+
# Individual checks — each returns an Array of finding Hashes. A finding has: :check, :status (:pass/:fail/:warn),
|
|
103
|
+
# :message, :hint
|
|
105
104
|
# ------------------------------------------------------------------
|
|
106
105
|
|
|
107
106
|
def audit_config(configuration)
|
|
@@ -219,8 +218,8 @@ module Rigor
|
|
|
219
218
|
]
|
|
220
219
|
end
|
|
221
220
|
|
|
222
|
-
# True when Rails is in Gemfile.lock but the config enables no
|
|
223
|
-
#
|
|
221
|
+
# True when Rails is in Gemfile.lock but the config enables no Rails plugin — the same probe {ProjectStateProbe}
|
|
222
|
+
# uses.
|
|
224
223
|
def rails_unconfigured?(_configuration)
|
|
225
224
|
config_path = Configuration.discover
|
|
226
225
|
return false if config_path.nil?
|
|
@@ -8,16 +8,13 @@ require_relative "command"
|
|
|
8
8
|
|
|
9
9
|
module Rigor
|
|
10
10
|
class CLI
|
|
11
|
-
# Executes `rigor explain <rule>`. Prints the catalog entry for
|
|
12
|
-
#
|
|
13
|
-
# (`call`, `flow`, `assert`, `dump`, `def`).
|
|
11
|
+
# Executes `rigor explain <rule>`. Prints the catalog entry for one canonical rule id, a legacy alias, or a family
|
|
12
|
+
# wildcard (`call`, `flow`, `assert`, `dump`, `def`).
|
|
14
13
|
#
|
|
15
14
|
# Without arguments lists every rule's id and one-line summary.
|
|
16
15
|
#
|
|
17
|
-
# The command is read-only: no parser, no analyzer, no I/O
|
|
18
|
-
#
|
|
19
|
-
# diagnostic in the editor and wants to know what the rule
|
|
20
|
-
# means without leaving the terminal.
|
|
16
|
+
# The command is read-only: no parser, no analyzer, no I/O beyond the rendered catalog. Useful when a user sees a
|
|
17
|
+
# diagnostic in the editor and wants to know what the rule means without leaving the terminal.
|
|
21
18
|
class ExplainCommand < Command
|
|
22
19
|
USAGE = "Usage: rigor explain [options] [<rule>]"
|
|
23
20
|
|
|
@@ -4,11 +4,10 @@ require "json"
|
|
|
4
4
|
|
|
5
5
|
module Rigor
|
|
6
6
|
class CLI
|
|
7
|
-
# Renders a {FusedProtectionReport} (ADR-70) as text or JSON. The text form
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
#
|
|
11
|
-
# *where to add protection*, never "your code is broken".
|
|
7
|
+
# Renders a {FusedProtectionReport} (ADR-70) as text or JSON. The text form leads with the fused protected ratio
|
|
8
|
+
# (caught by *either* a type or a test), splits it into the two axes, then lists the unprotected breakages ("add a
|
|
9
|
+
# type or a test here") and the least-protected files. The framing is always *where to add protection*, never "your
|
|
10
|
+
# code is broken".
|
|
12
11
|
class FusedProtectionRenderer
|
|
13
12
|
TOP_CALLS = 15
|
|
14
13
|
TOP_FILES = 10
|
|
@@ -2,15 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
module Rigor
|
|
4
4
|
class CLI
|
|
5
|
-
# ADR-70 — aggregates per-file {Protection::MutationScanner::FusedFileResult}
|
|
6
|
-
#
|
|
7
|
-
#
|
|
8
|
-
#
|
|
9
|
-
# ranked "add a type OR a test here" list.
|
|
5
|
+
# ADR-70 — aggregates per-file {Protection::MutationScanner::FusedFileResult} into a project-level **fused**
|
|
6
|
+
# protection report: how many type-visible breakages were caught by the type checker, how many of the
|
|
7
|
+
# *type-survivors* were caught by the test suite, and which sites neither axis caught — the ranked "add a type OR a
|
|
8
|
+
# test here" list.
|
|
10
9
|
#
|
|
11
|
-
# Framing (ADR-63 / ADR-62 Criterion A, extended): the payload is the
|
|
12
|
-
#
|
|
13
|
-
# An unprotected site is "add protection here", never "your code is broken".
|
|
10
|
+
# Framing (ADR-63 / ADR-62 Criterion A, extended): the payload is the **attribution** — which protection axis is
|
|
11
|
+
# missing — never raw survival. An unprotected site is "add protection here", never "your code is broken".
|
|
14
12
|
FusedFileProtection = Data.define(:path, :type_killed, :test_killed, :unprotected, :ratio)
|
|
15
13
|
UnprotectedBreakage = Data.define(:method_name, :count, :examples)
|
|
16
14
|
|
|
@@ -9,8 +9,8 @@ module Rigor
|
|
|
9
9
|
class CLI
|
|
10
10
|
# Executes the `rigor lsp` command.
|
|
11
11
|
#
|
|
12
|
-
# Starts a long-running LSP server over stdio (JSON-RPC).
|
|
13
|
-
#
|
|
12
|
+
# Starts a long-running LSP server over stdio (JSON-RPC). See `docs/design/20260517-language-server.md` for the
|
|
13
|
+
# design.
|
|
14
14
|
class LspCommand < Command
|
|
15
15
|
USAGE = "Usage: rigor lsp [options]"
|
|
16
16
|
|
|
@@ -29,13 +29,10 @@ module Rigor
|
|
|
29
29
|
require_relative "../configuration"
|
|
30
30
|
require "language_server-protocol"
|
|
31
31
|
|
|
32
|
-
# STDIN is read frame-by-frame via the gem's `Io::Reader`;
|
|
33
|
-
#
|
|
34
|
-
#
|
|
35
|
-
#
|
|
36
|
-
# until either STDIN hits EOF or `server.exited?`; the
|
|
37
|
-
# process then exits with the server's recorded code
|
|
38
|
-
# (0 after a clean shutdown+exit, 1 otherwise).
|
|
32
|
+
# STDIN is read frame-by-frame via the gem's `Io::Reader`; STDOUT is wrapped in `SynchronizedWriter` so
|
|
33
|
+
# concurrent writes from the main dispatch thread + the Debouncer's async threads don't interleave frames. The
|
|
34
|
+
# Loop runs until either STDIN hits EOF or `server.exited?`; the process then exits with the server's recorded
|
|
35
|
+
# code (0 after a clean shutdown+exit, 1 otherwise).
|
|
39
36
|
writer = LanguageServer::SynchronizedWriter.new(
|
|
40
37
|
::LanguageServer::Protocol::Transport::Io::Writer.new($stdout)
|
|
41
38
|
)
|
|
@@ -46,19 +43,14 @@ module Rigor
|
|
|
46
43
|
|
|
47
44
|
private
|
|
48
45
|
|
|
49
|
-
# Builds the full collaborator graph from a fresh
|
|
50
|
-
# `
|
|
51
|
-
# loop]` so the caller drives the loop and reads
|
|
52
|
-
# `server.exit_code` for the process exit status.
|
|
46
|
+
# Builds the full collaborator graph from a fresh `Configuration` + `ProjectContext`. Returns `[server, loop]` so
|
|
47
|
+
# the caller drives the loop and reads `server.exit_code` for the process exit status.
|
|
53
48
|
def build_server(writer:, config_path:) # rubocop:disable Metrics/MethodLength
|
|
54
49
|
configuration = Configuration.load(config_path)
|
|
55
|
-
# ProjectContext caches Environment + Cache::Store across
|
|
56
|
-
#
|
|
57
|
-
# by `workspace/didChangeWatchedFiles` and
|
|
58
|
-
# `workspace/didChangeConfiguration`.
|
|
50
|
+
# ProjectContext caches Environment + Cache::Store across requests so hover / publish hit the warm path.
|
|
51
|
+
# Invalidated by `workspace/didChangeWatchedFiles` and `workspace/didChangeConfiguration`.
|
|
59
52
|
project_context = LanguageServer::ProjectContext.new(configuration: configuration)
|
|
60
|
-
# Single source of truth for buffer state — threaded to
|
|
61
|
-
# Server + all three providers.
|
|
53
|
+
# Single source of truth for buffer state — threaded to Server + all three providers.
|
|
62
54
|
buffer_table = LanguageServer::BufferTable.new
|
|
63
55
|
debouncer = LanguageServer::Debouncer.new
|
|
64
56
|
publisher = LanguageServer::DiagnosticPublisher.new(
|
|
@@ -8,13 +8,11 @@ module Rigor
|
|
|
8
8
|
class CLI
|
|
9
9
|
# Executes the `rigor mcp` command.
|
|
10
10
|
#
|
|
11
|
-
# Starts a long-running MCP (Model Context Protocol) server over stdio.
|
|
12
|
-
#
|
|
13
|
-
# newline-delimited JSON-RPC 2.0 stream. See ADR-33.
|
|
11
|
+
# Starts a long-running MCP (Model Context Protocol) server over stdio. The server exposes Rigor's analysis tools as
|
|
12
|
+
# MCP tool calls over a newline-delimited JSON-RPC 2.0 stream. See ADR-33.
|
|
14
13
|
#
|
|
15
|
-
# Slice 1 ships the stdio transport with seven read-only tools:
|
|
16
|
-
#
|
|
17
|
-
# rigor_sig_gen, rigor_explain, rigor_coverage.
|
|
14
|
+
# Slice 1 ships the stdio transport with seven read-only tools: rigor_check, rigor_type_of, rigor_triage,
|
|
15
|
+
# rigor_annotate, rigor_sig_gen, rigor_explain, rigor_coverage.
|
|
18
16
|
class McpCommand < Command
|
|
19
17
|
USAGE = "Usage: rigor mcp [options]"
|
|
20
18
|
|
|
@@ -4,10 +4,9 @@ require "json"
|
|
|
4
4
|
|
|
5
5
|
module Rigor
|
|
6
6
|
class CLI
|
|
7
|
-
# Renders a {MutationProtectionReport} (ADR-63 Tier 2) as text or JSON. The
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
# The framing is always *where to add a type*, never "your code is broken".
|
|
7
|
+
# Renders a {MutationProtectionReport} (ADR-63 Tier 2) as text or JSON. The text form leads with the effectiveness
|
|
8
|
+
# ratio (caught breakages), then the breakages Rigor missed ("add a type here"), then the least-effective files. The
|
|
9
|
+
# framing is always *where to add a type*, never "your code is broken".
|
|
11
10
|
class MutationProtectionRenderer
|
|
12
11
|
TOP_CALLS = 15
|
|
13
12
|
TOP_FILES = 10
|
|
@@ -2,16 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
module Rigor
|
|
4
4
|
class CLI
|
|
5
|
-
# ADR-63 Tier 2 — aggregates per-file {Protection::MutationScanner}
|
|
6
|
-
#
|
|
7
|
-
# a type
|
|
8
|
-
#
|
|
9
|
-
# breakage Rigor most often *missed* — the sites where a receiver annotation
|
|
10
|
-
# would buy real catching power.
|
|
5
|
+
# ADR-63 Tier 2 — aggregates per-file {Protection::MutationScanner} results into a project-level *effectiveness*
|
|
6
|
+
# report: the kill ratio (when a type-visible bug was introduced, how often Rigor caught it), the per-file
|
|
7
|
+
# breakdown, and a ranked "add a type here" list keyed by the method whose breakage Rigor most often *missed* — the
|
|
8
|
+
# sites where a receiver annotation would buy real catching power.
|
|
11
9
|
#
|
|
12
|
-
# The framing is load-bearing (ADR-63 Criterion A / ADR-62 Criterion A): the
|
|
13
|
-
#
|
|
14
|
-
# add a type*, never "your code is broken".
|
|
10
|
+
# The framing is load-bearing (ADR-63 Criterion A / ADR-62 Criterion A): the number is *effectiveness*, the
|
|
11
|
+
# survivors are *missed breakages / where to add a type*, never "your code is broken".
|
|
15
12
|
FileEffectiveness = Data.define(:path, :killed, :survived, :ratio)
|
|
16
13
|
MissedBreakage = Data.define(:method_name, :count, :examples)
|
|
17
14
|
|
data/lib/rigor/cli/options.rb
CHANGED
|
@@ -6,28 +6,22 @@ module Rigor
|
|
|
6
6
|
class CLI
|
|
7
7
|
# Shared option plumbing for the subcommands.
|
|
8
8
|
#
|
|
9
|
-
# Today it owns the editor-mode surface that `rigor check` and
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
#
|
|
13
|
-
# `TypeOfCommand`, so a fix to one (the paired-flag check, the
|
|
14
|
-
# readability check, the error wording) could silently miss the
|
|
15
|
-
# other. Centralising it keeps the two editor-mode entry points in
|
|
9
|
+
# Today it owns the editor-mode surface that `rigor check` and `rigor type-of` both expose: the `--tmp-file` /
|
|
10
|
+
# `--instead-of` flag pair and the buffer-binding resolution that validates it. That resolution used to be copied
|
|
11
|
+
# verbatim into both `Rigor::CLI` and `TypeOfCommand`, so a fix to one (the paired-flag check, the readability
|
|
12
|
+
# check, the error wording) could silently miss the other. Centralising it keeps the two editor-mode entry points in
|
|
16
13
|
# lockstep.
|
|
17
14
|
module Options
|
|
18
15
|
module_function
|
|
19
16
|
|
|
20
|
-
# Defines the standard `--config=PATH` flag on `parser`, writing the
|
|
21
|
-
#
|
|
22
|
-
#
|
|
23
|
-
# bespoke (`diff`, `mcp`, `show-bleedingedge`) keep their own
|
|
24
|
-
# `parser.on` rather than this shared wording.
|
|
17
|
+
# Defines the standard `--config=PATH` flag on `parser`, writing the path into `options[:config]`. Used by every
|
|
18
|
+
# subcommand that loads a `.rigor.yml`; the few whose `--config` help text is intentionally bespoke (`diff`,
|
|
19
|
+
# `mcp`, `show-bleedingedge`) keep their own `parser.on` rather than this shared wording.
|
|
25
20
|
def add_config(parser, options)
|
|
26
21
|
parser.on("--config=PATH", "Path to the Rigor configuration file") { |value| options[:config] = value }
|
|
27
22
|
end
|
|
28
23
|
|
|
29
|
-
# Defines the `--tmp-file` / `--instead-of` editor-mode flag pair
|
|
30
|
-
# on `parser`, writing into `options`.
|
|
24
|
+
# Defines the `--tmp-file` / `--instead-of` editor-mode flag pair on `parser`, writing into `options`.
|
|
31
25
|
def add_editor_mode(parser, options)
|
|
32
26
|
parser.on("--tmp-file=PATH",
|
|
33
27
|
"Editor mode: read source bytes from PATH instead of --instead-of (paired)") do |value|
|
|
@@ -39,11 +33,9 @@ module Rigor
|
|
|
39
33
|
end
|
|
40
34
|
end
|
|
41
35
|
|
|
42
|
-
# Resolves the editor-mode buffer binding from parsed `options`:
|
|
43
|
-
#
|
|
44
|
-
#
|
|
45
|
-
# `:usage_error` (after writing the reason to `err`) when the flags
|
|
46
|
-
# are unpaired or the temp file is unreadable.
|
|
36
|
+
# Resolves the editor-mode buffer binding from parsed `options`: returns nil when neither editor-mode flag is set,
|
|
37
|
+
# a `Analysis::BufferBinding` when the pair is valid, or `:usage_error` (after writing the reason to `err`) when
|
|
38
|
+
# the flags are unpaired or the temp file is unreadable.
|
|
47
39
|
def resolve_buffer_binding(options, err:)
|
|
48
40
|
tmp = options[:tmp_file]
|
|
49
41
|
instead = options[:instead_of]
|
|
@@ -4,23 +4,17 @@ require_relative "command"
|
|
|
4
4
|
|
|
5
5
|
module Rigor
|
|
6
6
|
class CLI
|
|
7
|
-
# `rigor plugin` (singular) — discover and read the plugin source
|
|
8
|
-
# bundled with the `rigortype` gem.
|
|
7
|
+
# `rigor plugin` (singular) — discover and read the plugin source bundled with the `rigortype` gem.
|
|
9
8
|
#
|
|
10
|
-
# Rigor ships ~30 production plugins under `plugins/` and a set of
|
|
11
|
-
#
|
|
12
|
-
#
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
# instead of guessing the `Rigor::Plugin::Base` surface from prose.
|
|
16
|
-
# This command outputs the absolute paths so they can be found and
|
|
17
|
-
# read regardless of where the gem landed.
|
|
9
|
+
# Rigor ships ~30 production plugins under `plugins/` and a set of tutorial plugins under `examples/`. When Rigor is
|
|
10
|
+
# installed via `mise` / `gem install` the gem checkout is on disk, so a plugin author (or an AI coding agent
|
|
11
|
+
# following the `rigor-plugin-author` skill) can read a real, working plugin as a worked example — instead of
|
|
12
|
+
# guessing the `Rigor::Plugin::Base` surface from prose. This command outputs the absolute paths so they can be
|
|
13
|
+
# found and read regardless of where the gem landed.
|
|
18
14
|
#
|
|
19
|
-
# It is deliberately distinct from `rigor plugins` (plural), which
|
|
20
|
-
#
|
|
21
|
-
#
|
|
22
|
-
# in the *toolchain*. Mnemonic: "plugins" = my config; "plugin" =
|
|
23
|
-
# the catalogue I can learn from.
|
|
15
|
+
# It is deliberately distinct from `rigor plugins` (plural), which reports the activation status of the plugins
|
|
16
|
+
# configured in *your* `.rigor.yml`. This command (singular) browses the plugins bundled in the *toolchain*.
|
|
17
|
+
# Mnemonic: "plugins" = my config; "plugin" = the catalogue I can learn from.
|
|
24
18
|
#
|
|
25
19
|
# Subcommands:
|
|
26
20
|
#
|
|
@@ -39,13 +33,10 @@ module Rigor
|
|
|
39
33
|
#
|
|
40
34
|
# `rigor plugin` with no subcommand is an alias for `list`.
|
|
41
35
|
#
|
|
42
|
-
# **Docker / cross-filesystem note.** Every path printed is resolved
|
|
43
|
-
#
|
|
44
|
-
#
|
|
45
|
-
#
|
|
46
|
-
# will not resolve — read them from the same environment that ran
|
|
47
|
-
# the command (`rigor plugin print` inlines the body for exactly
|
|
48
|
-
# this case: it works with no file-reading tool at all).
|
|
36
|
+
# **Docker / cross-filesystem note.** Every path printed is resolved at runtime from this file's location, so it is
|
|
37
|
+
# correct *on the filesystem where `rigor` runs*. If you run `rigor` inside a container but read files from the host
|
|
38
|
+
# (or vice versa), the paths will not resolve — read them from the same environment that ran the command (`rigor
|
|
39
|
+
# plugin print` inlines the body for exactly this case: it works with no file-reading tool at all).
|
|
49
40
|
class PluginCommand < Command
|
|
50
41
|
USAGE = <<~USAGE
|
|
51
42
|
Usage: rigor plugin <subcommand> [args]
|
|
@@ -67,9 +58,8 @@ module Rigor
|
|
|
67
58
|
rigor plugin root
|
|
68
59
|
USAGE
|
|
69
60
|
|
|
70
|
-
# The bundled plugins/examples/source live at `<gem_root>/...`.
|
|
71
|
-
#
|
|
72
|
-
# directories up (matching SkillCommand::SKILLS_ROOT).
|
|
61
|
+
# The bundled plugins/examples/source live at `<gem_root>/...`. From `lib/rigor/cli/plugin_command.rb` the gem
|
|
62
|
+
# root is three directories up (matching SkillCommand::SKILLS_ROOT).
|
|
73
63
|
GEM_ROOT = File.expand_path("../../..", __dir__)
|
|
74
64
|
PLUGINS_ROOT = File.join(GEM_ROOT, "plugins")
|
|
75
65
|
EXAMPLES_ROOT = File.join(GEM_ROOT, "examples")
|
|
@@ -168,9 +158,8 @@ module Rigor
|
|
|
168
158
|
0
|
|
169
159
|
end
|
|
170
160
|
|
|
171
|
-
# The header that precedes the plugin body when an author runs
|
|
172
|
-
#
|
|
173
|
-
# output stays readable; the Ruby body below it is unchanged.
|
|
161
|
+
# The header that precedes the plugin body when an author runs `rigor plugin print <name>`. `# `-prefixed so the
|
|
162
|
+
# combined output stays readable; the Ruby body below it is unchanged.
|
|
174
163
|
def render_print_header(plugin)
|
|
175
164
|
dir = plugin.fetch(:path)
|
|
176
165
|
sig = File.join(dir, "sig")
|
|
@@ -202,8 +191,7 @@ module Rigor
|
|
|
202
191
|
end
|
|
203
192
|
end
|
|
204
193
|
|
|
205
|
-
# Match the directory name with or without the conventional
|
|
206
|
-
# `rigor-` prefix, so both `rigor-activerecord` and
|
|
194
|
+
# Match the directory name with or without the conventional `rigor-` prefix, so both `rigor-activerecord` and
|
|
207
195
|
# `activerecord` resolve.
|
|
208
196
|
def find(name)
|
|
209
197
|
all = discover(PLUGINS_ROOT) + discover(EXAMPLES_ROOT)
|