rigortype 0.3.7 → 0.3.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (450) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/data/capability_roles/capability_roles.rbs +36 -0
  4. data/data/gem_overlay/activesupport/core_ext.rbs +109 -13
  5. data/docs/handbook/02-everyday-types.md +17 -14
  6. data/docs/handbook/03-narrowing.md +37 -4
  7. data/docs/handbook/05-methods-and-blocks.md +1 -1
  8. data/docs/handbook/06-classes.md +2 -2
  9. data/docs/handbook/07-rbs-and-extended.md +14 -1
  10. data/docs/handbook/11-sig-gen.md +96 -15
  11. data/docs/handbook/README.md +1 -1
  12. data/docs/handbook/appendix-elixir.md +2 -2
  13. data/docs/handbook/appendix-go.md +2 -2
  14. data/docs/handbook/appendix-java-csharp.md +2 -2
  15. data/docs/handbook/appendix-mypy.md +2 -2
  16. data/docs/handbook/appendix-phpstan.md +1 -1
  17. data/docs/handbook/appendix-rust.md +1 -1
  18. data/docs/handbook/appendix-type-theory.md +4 -4
  19. data/docs/handbook/appendix-typescript.md +1 -1
  20. data/docs/llms.txt +2 -0
  21. data/docs/manual/02-cli-reference.md +39 -4
  22. data/docs/manual/03-configuration.md +11 -0
  23. data/docs/manual/04-diagnostics.md +12 -1
  24. data/docs/manual/07-plugins.md +15 -5
  25. data/docs/manual/08-skills.md +23 -2
  26. data/docs/manual/11-ci.md +9 -0
  27. data/docs/manual/15-type-protection-coverage.md +8 -0
  28. data/docs/manual/16-rbs-extended-annotations.md +6 -1
  29. data/docs/manual/18-removing-dead-code.md +10 -8
  30. data/docs/manual/plugins/rigor-actionpack.md +18 -0
  31. data/docs/manual/plugins/rigor-activerecord.md +28 -0
  32. data/docs/manual/plugins/rigor-activesupport-core-ext.md +32 -2
  33. data/docs/manual/plugins/rigor-rbs-inline.md +42 -1
  34. data/lib/rigor/analysis/baseline.rb +2 -2
  35. data/lib/rigor/analysis/check_rules/always_truthy_condition_collector.rb +1 -1
  36. data/lib/rigor/analysis/check_rules/dead_version_guard_arms.rb +1 -5
  37. data/lib/rigor/analysis/check_rules/ivar_write_collector.rb +10 -2
  38. data/lib/rigor/analysis/check_rules/main_pass_collector.rb +1 -1
  39. data/lib/rigor/analysis/check_rules/published_constant_guard.rb +15 -6
  40. data/lib/rigor/analysis/check_rules/rule_ids.rb +1 -1
  41. data/lib/rigor/analysis/check_rules/rule_walk.rb +39 -4
  42. data/lib/rigor/analysis/check_rules/self_closedness_scanner.rb +1 -1
  43. data/lib/rigor/analysis/check_rules/shadowed_rescue_collector.rb +1 -1
  44. data/lib/rigor/analysis/check_rules/unreachable_clause_collector.rb +2 -2
  45. data/lib/rigor/analysis/check_rules/void_value_use_collector.rb +0 -1
  46. data/lib/rigor/analysis/check_rules.rb +200 -32
  47. data/lib/rigor/analysis/crash_signature.rb +69 -13
  48. data/lib/rigor/analysis/dependency_source_inference/boundary_cross_reporter.rb +1 -1
  49. data/lib/rigor/analysis/dependency_source_inference/builder.rb +0 -2
  50. data/lib/rigor/analysis/dependency_source_inference/gem_resolver.rb +0 -2
  51. data/lib/rigor/analysis/dependency_source_inference/index.rb +5 -5
  52. data/lib/rigor/analysis/dependency_source_inference/return_type_heuristic.rb +1 -2
  53. data/lib/rigor/analysis/dependency_source_inference/walker.rb +4 -4
  54. data/lib/rigor/analysis/effects_cache_probe.rb +3 -4
  55. data/lib/rigor/analysis/erb_template_detector.rb +1 -2
  56. data/lib/rigor/analysis/fact_store.rb +6 -1
  57. data/lib/rigor/analysis/incremental.rb +16 -0
  58. data/lib/rigor/analysis/incremental_session.rb +100 -29
  59. data/lib/rigor/analysis/plugin_fact_fingerprint.rb +0 -1
  60. data/lib/rigor/analysis/reachability/graph.rb +3 -5
  61. data/lib/rigor/analysis/reachability/plugin_roots.rb +6 -5
  62. data/lib/rigor/analysis/reachability/project_files.rb +2 -2
  63. data/lib/rigor/analysis/reachability/scan.rb +5 -5
  64. data/lib/rigor/analysis/reachability/scan_cache.rb +2 -2
  65. data/lib/rigor/analysis/reachability/signature_scan.rb +2 -2
  66. data/lib/rigor/analysis/result.rb +1 -3
  67. data/lib/rigor/analysis/rule_catalog.rb +4 -1
  68. data/lib/rigor/analysis/run_cache_key.rb +1 -1
  69. data/lib/rigor/analysis/run_cache_probe.rb +3 -5
  70. data/lib/rigor/analysis/runner/buffer_pool_dispatcher.rb +6 -8
  71. data/lib/rigor/analysis/runner/declaration_position.rb +1 -2
  72. data/lib/rigor/analysis/runner/diagnostic_aggregator.rb +316 -40
  73. data/lib/rigor/analysis/runner/effect_annotation_residual_pass.rb +2 -3
  74. data/lib/rigor/analysis/runner/effect_envelope_pass.rb +9 -10
  75. data/lib/rigor/analysis/runner/pool_coordinator.rb +430 -77
  76. data/lib/rigor/analysis/runner/project_pre_passes.rb +12 -6
  77. data/lib/rigor/analysis/runner/run_snapshots.rb +13 -3
  78. data/lib/rigor/analysis/runner.rb +200 -43
  79. data/lib/rigor/analysis/worker_session.rb +36 -12
  80. data/lib/rigor/bleeding_edge.rb +12 -24
  81. data/lib/rigor/builtins/hkt_builtins.rb +2 -2
  82. data/lib/rigor/builtins/imported_refinements.rb +166 -30
  83. data/lib/rigor/builtins/predefined_constant_refinements.rb +5 -7
  84. data/lib/rigor/builtins/regex_refinement.rb +4 -4
  85. data/lib/rigor/builtins/static_return_refinements.rb +5 -6
  86. data/lib/rigor/cache/annotation_location.rb +70 -0
  87. data/lib/rigor/cache/descriptor.rb +58 -20
  88. data/lib/rigor/cache/engine_source.rb +4 -4
  89. data/lib/rigor/cache/file_digest.rb +9 -1
  90. data/lib/rigor/cache/incremental_snapshot.rb +40 -6
  91. data/lib/rigor/cache/rbs_class_ancestor_table.rb +0 -3
  92. data/lib/rigor/cache/rbs_class_type_param_names.rb +0 -3
  93. data/lib/rigor/cache/rbs_constant_table.rb +0 -3
  94. data/lib/rigor/cache/rbs_descriptor.rb +79 -11
  95. data/lib/rigor/cache/rbs_environment.rb +8 -4
  96. data/lib/rigor/cache/rbs_environment_marshal_patch.rb +39 -0
  97. data/lib/rigor/cache/rbs_known_class_names.rb +0 -3
  98. data/lib/rigor/cache/store.rb +85 -33
  99. data/lib/rigor/cli/annotate_command.rb +5 -6
  100. data/lib/rigor/cli/check_command.rb +57 -10
  101. data/lib/rigor/cli/check_invocation.rb +6 -11
  102. data/lib/rigor/cli/check_runner_factory.rb +1 -5
  103. data/lib/rigor/cli/coverage_command.rb +1 -1
  104. data/lib/rigor/cli/coverage_mutation.rb +12 -3
  105. data/lib/rigor/cli/coverage_scan.rb +1 -5
  106. data/lib/rigor/cli/diff_command.rb +1 -1
  107. data/lib/rigor/cli/doc_links.rb +3 -3
  108. data/lib/rigor/cli/docs_command.rb +2 -2
  109. data/lib/rigor/cli/doctor_command.rb +85 -38
  110. data/lib/rigor/cli/effects_command.rb +2 -2
  111. data/lib/rigor/cli/effects_diff_renderer.rb +3 -3
  112. data/lib/rigor/cli/effects_snapshot_command.rb +1 -1
  113. data/lib/rigor/cli/explain_command.rb +34 -1
  114. data/lib/rigor/cli/fused_protection_report.rb +7 -1
  115. data/lib/rigor/cli/lsp_command.rb +1 -1
  116. data/lib/rigor/cli/mcp_command.rb +1 -1
  117. data/lib/rigor/cli/measurement_integrity_warning.rb +4 -5
  118. data/lib/rigor/cli/mutation_fork_scan.rb +6 -6
  119. data/lib/rigor/cli/mutation_protection_report.rb +7 -1
  120. data/lib/rigor/cli/plugin_command.rb +1 -1
  121. data/lib/rigor/cli/plugins_command.rb +2 -1
  122. data/lib/rigor/cli/prism_colorizer.rb +2 -2
  123. data/lib/rigor/cli/protection_fork_scan.rb +6 -6
  124. data/lib/rigor/cli/show_bleedingedge_command.rb +1 -1
  125. data/lib/rigor/cli/sig_gen_command.rb +31 -2
  126. data/lib/rigor/cli/skill_command.rb +1 -1
  127. data/lib/rigor/cli/skill_deep_probe.rb +4 -4
  128. data/lib/rigor/cli/skill_describe.rb +36 -35
  129. data/lib/rigor/cli/trace_command.rb +4 -4
  130. data/lib/rigor/cli/trace_renderer.rb +5 -6
  131. data/lib/rigor/cli/triage_command.rb +1 -1
  132. data/lib/rigor/cli/type_of_command.rb +10 -6
  133. data/lib/rigor/cli/type_scan_command.rb +4 -4
  134. data/lib/rigor/cli/unused_command.rb +11 -3
  135. data/lib/rigor/cli/upgrade_command.rb +1 -1
  136. data/lib/rigor/cli.rb +68 -6
  137. data/lib/rigor/config_audit.rb +30 -5
  138. data/lib/rigor/configuration/severity_profile.rb +6 -6
  139. data/lib/rigor/configuration.rb +43 -4
  140. data/lib/rigor/effects/attribution.rb +1 -3
  141. data/lib/rigor/effects/config_envelopes.rb +6 -8
  142. data/lib/rigor/effects/definition_lines.rb +25 -6
  143. data/lib/rigor/effects/effect_table.rb +0 -1
  144. data/lib/rigor/effects/entry_points.rb +0 -2
  145. data/lib/rigor/effects/envelope_check.rb +8 -8
  146. data/lib/rigor/effects/envelope_index.rb +5 -8
  147. data/lib/rigor/effects/framework_units.rb +4 -6
  148. data/lib/rigor/effects/identity.rb +4 -6
  149. data/lib/rigor/effects/inline_anchor.rb +7 -7
  150. data/lib/rigor/effects/label_intent.rb +3 -4
  151. data/lib/rigor/effects/liskov_check.rb +8 -8
  152. data/lib/rigor/effects/method_key.rb +1 -1
  153. data/lib/rigor/effects/plugin_facts.rb +4 -6
  154. data/lib/rigor/effects/propagator.rb +2 -3
  155. data/lib/rigor/effects/scanner.rb +1 -1
  156. data/lib/rigor/effects/signature_sources.rb +3 -5
  157. data/lib/rigor/effects/snapshot.rb +10 -10
  158. data/lib/rigor/effects/snapshot_diff.rb +1 -1
  159. data/lib/rigor/effects/unit_scan.rb +10 -10
  160. data/lib/rigor/effects/unknown_label_check.rb +3 -8
  161. data/lib/rigor/effects/unknown_label_report.rb +3 -4
  162. data/lib/rigor/environment/bundle_sig_discovery.rb +6 -6
  163. data/lib/rigor/environment/class_registry.rb +3 -1
  164. data/lib/rigor/environment/failure_slot.rb +28 -0
  165. data/lib/rigor/environment/installed_gem_set.rb +85 -0
  166. data/lib/rigor/environment/lockfile_resolver.rb +51 -4
  167. data/lib/rigor/environment/missing_gem_constant_index.rb +4 -4
  168. data/lib/rigor/environment/rbs_collection_discovery.rb +5 -5
  169. data/lib/rigor/environment/rbs_coverage_report.rb +5 -5
  170. data/lib/rigor/environment/rbs_hierarchy.rb +3 -1
  171. data/lib/rigor/environment/rbs_loader.rb +613 -113
  172. data/lib/rigor/environment.rb +189 -27
  173. data/lib/rigor/flow_contribution/merger.rb +0 -2
  174. data/lib/rigor/flow_contribution.rb +11 -13
  175. data/lib/rigor/inference/acceptance.rb +153 -8
  176. data/lib/rigor/inference/block_parameter_binder.rb +2 -3
  177. data/lib/rigor/inference/body_fixpoint.rb +5 -5
  178. data/lib/rigor/inference/budget_trace.rb +1 -5
  179. data/lib/rigor/inference/captured_locals.rb +2 -3
  180. data/lib/rigor/inference/closure_escape_analyzer.rb +2 -4
  181. data/lib/rigor/inference/coverage_scanner.rb +4 -6
  182. data/lib/rigor/inference/dynamic_origin.rb +1 -1
  183. data/lib/rigor/inference/element_read_widening.rb +168 -0
  184. data/lib/rigor/inference/expression_typer.rb +763 -143
  185. data/lib/rigor/inference/fork_map.rb +5 -7
  186. data/lib/rigor/inference/hkt_reducer.rb +2 -3
  187. data/lib/rigor/inference/hkt_registry.rb +19 -10
  188. data/lib/rigor/inference/hkt_sugar_translator.rb +15 -21
  189. data/lib/rigor/inference/index_write_widening.rb +1 -5
  190. data/lib/rigor/inference/macro_block_self_type.rb +1 -4
  191. data/lib/rigor/inference/method_dispatcher/block_folding.rb +2 -9
  192. data/lib/rigor/inference/method_dispatcher/cgi_folding.rb +1 -1
  193. data/lib/rigor/inference/method_dispatcher/constant_folding.rb +305 -19
  194. data/lib/rigor/inference/method_dispatcher/data_folding.rb +1 -1
  195. data/lib/rigor/inference/method_dispatcher/file_folding.rb +1 -1
  196. data/lib/rigor/inference/method_dispatcher/iterator_dispatch.rb +2 -2
  197. data/lib/rigor/inference/method_dispatcher/json_folding.rb +1 -1
  198. data/lib/rigor/inference/method_dispatcher/kernel_dispatch.rb +7 -1
  199. data/lib/rigor/inference/method_dispatcher/math_folding.rb +41 -3
  200. data/lib/rigor/inference/method_dispatcher/method_folding.rb +2 -5
  201. data/lib/rigor/inference/method_dispatcher/overload_selector.rb +61 -47
  202. data/lib/rigor/inference/method_dispatcher/random_folding.rb +82 -0
  203. data/lib/rigor/inference/method_dispatcher/rbs_dispatch.rb +165 -31
  204. data/lib/rigor/inference/method_dispatcher/receiver_affinity.rb +25 -4
  205. data/lib/rigor/inference/method_dispatcher/reduce_folding.rb +2 -8
  206. data/lib/rigor/inference/method_dispatcher/regexp_folding.rb +1 -1
  207. data/lib/rigor/inference/method_dispatcher/set_folding.rb +1 -1
  208. data/lib/rigor/inference/method_dispatcher/shape_dispatch.rb +1 -1
  209. data/lib/rigor/inference/method_dispatcher/shellwords_folding.rb +1 -1
  210. data/lib/rigor/inference/method_dispatcher/singleton_mixin_dispatch.rb +1 -2
  211. data/lib/rigor/inference/method_dispatcher/struct_folding.rb +4 -5
  212. data/lib/rigor/inference/method_dispatcher/struct_materialization.rb +85 -4
  213. data/lib/rigor/inference/method_dispatcher/time_folding.rb +1 -1
  214. data/lib/rigor/inference/method_dispatcher/universal_object_dispatch.rb +1 -2
  215. data/lib/rigor/inference/method_dispatcher/uri_folding.rb +1 -1
  216. data/lib/rigor/inference/method_dispatcher.rb +12 -13
  217. data/lib/rigor/inference/method_parameter_binder.rb +4 -6
  218. data/lib/rigor/inference/multi_target_binder.rb +1 -3
  219. data/lib/rigor/inference/mutation_rejoin.rb +168 -0
  220. data/lib/rigor/inference/mutation_widening.rb +100 -51
  221. data/lib/rigor/inference/narrowing.rb +299 -46
  222. data/lib/rigor/inference/optimistic_origin.rb +1 -7
  223. data/lib/rigor/inference/origin_lookup.rb +2 -3
  224. data/lib/rigor/inference/parameter_inference_collector.rb +5 -6
  225. data/lib/rigor/inference/pre_eval_constants.rb +6 -5
  226. data/lib/rigor/inference/precision_scanner.rb +3 -4
  227. data/lib/rigor/inference/project_patched_methods.rb +2 -2
  228. data/lib/rigor/inference/project_patched_scanner.rb +3 -3
  229. data/lib/rigor/inference/protection_scanner.rb +1 -2
  230. data/lib/rigor/inference/range_constant.rb +57 -0
  231. data/lib/rigor/inference/rbs_type_translator.rb +49 -11
  232. data/lib/rigor/inference/receiver_alias.rb +3 -3
  233. data/lib/rigor/inference/refinement_mutation.rb +72 -0
  234. data/lib/rigor/inference/scope_indexer.rb +688 -151
  235. data/lib/rigor/inference/statement_evaluator.rb +221 -50
  236. data/lib/rigor/inference/string_mutation.rb +60 -0
  237. data/lib/rigor/inference/struct_fold_safety.rb +6 -7
  238. data/lib/rigor/inference/synthetic_method_index.rb +1 -2
  239. data/lib/rigor/inference/synthetic_method_scanner.rb +4 -6
  240. data/lib/rigor/inference/version_guard.rb +28 -21
  241. data/lib/rigor/inference/void_origin.rb +3 -3
  242. data/lib/rigor/inference/void_tail_summary.rb +2 -4
  243. data/lib/rigor/language_server/buffer_table.rb +4 -4
  244. data/lib/rigor/language_server/completion_provider.rb +1 -1
  245. data/lib/rigor/language_server/debouncer.rb +1 -1
  246. data/lib/rigor/language_server/diagnostic_publisher.rb +4 -4
  247. data/lib/rigor/language_server/document_symbol_provider.rb +1 -1
  248. data/lib/rigor/language_server/folding_range_provider.rb +1 -1
  249. data/lib/rigor/language_server/hover_provider.rb +1 -1
  250. data/lib/rigor/language_server/hover_renderer.rb +2 -2
  251. data/lib/rigor/language_server/incremental_sync.rb +6 -6
  252. data/lib/rigor/language_server/project_context.rb +2 -5
  253. data/lib/rigor/language_server/publish_batcher.rb +2 -2
  254. data/lib/rigor/language_server/selection_range_provider.rb +2 -2
  255. data/lib/rigor/language_server/server.rb +9 -9
  256. data/lib/rigor/language_server/signature_help_provider.rb +1 -1
  257. data/lib/rigor/language_server/uri.rb +1 -1
  258. data/lib/rigor/plugin/base.rb +90 -21
  259. data/lib/rigor/plugin/bundled_catalog.rb +167 -0
  260. data/lib/rigor/plugin/effect_attribution.rb +7 -7
  261. data/lib/rigor/plugin/effect_entry_points.rb +3 -3
  262. data/lib/rigor/plugin/fact_store.rb +6 -6
  263. data/lib/rigor/plugin/io_boundary.rb +93 -8
  264. data/lib/rigor/plugin/isolation.rb +29 -6
  265. data/lib/rigor/plugin/loader.rb +31 -12
  266. data/lib/rigor/plugin/macro/heredoc_template.rb +1 -1
  267. data/lib/rigor/plugin/macro/trait_registry.rb +1 -1
  268. data/lib/rigor/plugin/manifest.rb +23 -1
  269. data/lib/rigor/plugin/registry.rb +67 -14
  270. data/lib/rigor/plugin/source_rbs_synthesis_reporter.rb +12 -1
  271. data/lib/rigor/plugin/trust_policy.rb +2 -4
  272. data/lib/rigor/plugin/type_node_resolver.rb +3 -3
  273. data/lib/rigor/plugin_gap_advisory.rb +96 -0
  274. data/lib/rigor/project_environment.rb +138 -0
  275. data/lib/rigor/protection/analysis_guard.rb +93 -14
  276. data/lib/rigor/protection/closure_kill_oracle.rb +67 -23
  277. data/lib/rigor/protection/dependency_closure.rb +5 -8
  278. data/lib/rigor/protection/diagnostic_oracle.rb +2 -2
  279. data/lib/rigor/protection/discovery_seed.rb +11 -11
  280. data/lib/rigor/protection/kill_signature.rb +2 -4
  281. data/lib/rigor/protection/measurement_integrity.rb +1 -3
  282. data/lib/rigor/protection/mutation_cache.rb +6 -9
  283. data/lib/rigor/protection/mutation_scanner.rb +12 -15
  284. data/lib/rigor/protection/mutator.rb +2 -1
  285. data/lib/rigor/protection/test_suite_oracle.rb +5 -5
  286. data/lib/rigor/rbs_extended/conformance_checker.rb +4 -3
  287. data/lib/rigor/rbs_extended/envelope_scanner.rb +12 -13
  288. data/lib/rigor/rbs_extended/hkt_directives.rb +16 -1
  289. data/lib/rigor/rbs_extended/reporter.rb +122 -16
  290. data/lib/rigor/rbs_extended.rb +67 -22
  291. data/lib/rigor/reflection/constant_path.rb +126 -0
  292. data/lib/rigor/reflection.rb +26 -10
  293. data/lib/rigor/runtime/jit.rb +6 -8
  294. data/lib/rigor/scope/discovery_index.rb +30 -0
  295. data/lib/rigor/scope.rb +203 -4
  296. data/lib/rigor/sig_gen/generator.rb +181 -102
  297. data/lib/rigor/sig_gen/layout_index.rb +3 -4
  298. data/lib/rigor/sig_gen/meta_class_shape.rb +3 -5
  299. data/lib/rigor/sig_gen/observation_collector.rb +17 -15
  300. data/lib/rigor/sig_gen/path_mapper.rb +4 -6
  301. data/lib/rigor/sig_gen/rbs_validity.rb +4 -4
  302. data/lib/rigor/sig_gen/renderer.rb +17 -11
  303. data/lib/rigor/sig_gen/skip_reason_catalog.rb +111 -0
  304. data/lib/rigor/sig_gen/superclass_spelling.rb +27 -0
  305. data/lib/rigor/sig_gen/type_elaborator.rb +1 -3
  306. data/lib/rigor/sig_gen/writer.rb +23 -6
  307. data/lib/rigor/signature_path_audit.rb +153 -6
  308. data/lib/rigor/source/literals.rb +0 -23
  309. data/lib/rigor/source/node_children.rb +0 -2
  310. data/lib/rigor/source/node_locator.rb +5 -11
  311. data/lib/rigor/source/node_walker.rb +2 -5
  312. data/lib/rigor/triage/catalogue.rb +1 -3
  313. data/lib/rigor/triage.rb +3 -5
  314. data/lib/rigor/type/accepts_result.rb +24 -6
  315. data/lib/rigor/type/combinator.rb +68 -5
  316. data/lib/rigor/type/data_class.rb +2 -2
  317. data/lib/rigor/type/data_instance.rb +4 -4
  318. data/lib/rigor/type/float_range.rb +128 -0
  319. data/lib/rigor/type/hash_shape.rb +5 -5
  320. data/lib/rigor/type/integer_range.rb +13 -8
  321. data/lib/rigor/type/nominal.rb +8 -2
  322. data/lib/rigor/type/refined.rb +3 -3
  323. data/lib/rigor/type/struct_class.rb +3 -3
  324. data/lib/rigor/type/struct_instance.rb +4 -4
  325. data/lib/rigor/type.rb +1 -0
  326. data/lib/rigor/type_node/generic.rb +1 -1
  327. data/lib/rigor/type_node/range_literal.rb +25 -0
  328. data/lib/rigor/type_node/resolver_chain.rb +1 -1
  329. data/lib/rigor/type_node.rb +1 -0
  330. data/lib/rigor/version.rb +1 -1
  331. data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/analyzer.rb +0 -4
  332. data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_discoverer.rb +0 -1
  333. data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_index.rb +0 -2
  334. data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable.rb +1 -0
  335. data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/analyzer.rb +0 -4
  336. data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_discoverer.rb +3 -5
  337. data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_index.rb +1 -4
  338. data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer.rb +1 -0
  339. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/analyzer.rb +33 -30
  340. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_discoverer.rb +0 -1
  341. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_index.rb +1 -3
  342. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack.rb +28 -2
  343. data/plugins/rigor-actionpack/sig/action_controller.rbs +71 -0
  344. data/plugins/rigor-activejob/lib/rigor/plugin/activejob/analyzer.rb +0 -4
  345. data/plugins/rigor-activejob/lib/rigor/plugin/activejob/effects.rb +1 -1
  346. data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_discoverer.rb +0 -1
  347. data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_index.rb +0 -2
  348. data/plugins/rigor-activejob/lib/rigor/plugin/activejob/recurring_scan.rb +1 -1
  349. data/plugins/rigor-activejob/lib/rigor/plugin/activejob.rb +1 -0
  350. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_discoverer.rb +3 -4
  351. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_parser.rb +1 -2
  352. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/structure_sql_parser.rb +1 -2
  353. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord.rb +42 -7
  354. data/plugins/rigor-activerecord/sig/active_record/framework.rbs +123 -0
  355. data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage.rb +1 -0
  356. data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext.rb +9 -2
  357. data/plugins/rigor-activesupport-core-ext/sig/active_support/core_ext.rbs +119 -14
  358. data/plugins/rigor-devise/lib/rigor/plugin/devise.rb +1 -0
  359. data/plugins/rigor-dry-monads/lib/rigor/plugin/dry_monads.rb +1 -0
  360. data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema/schema_scanner.rb +9 -7
  361. data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema.rb +7 -3
  362. data/plugins/rigor-dry-struct/lib/rigor/plugin/dry_struct.rb +1 -0
  363. data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types/alias_scanner.rb +8 -6
  364. data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types.rb +11 -7
  365. data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation/contract_scanner.rb +13 -11
  366. data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation.rb +9 -4
  367. data/plugins/rigor-ethon/lib/rigor/plugin/ethon.rb +1 -0
  368. data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/analyzer.rb +0 -5
  369. data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_discoverer.rb +0 -1
  370. data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_index.rb +0 -1
  371. data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot.rb +8 -1
  372. data/plugins/rigor-ffi/lib/rigor/plugin/ffi.rb +36 -4
  373. data/plugins/rigor-ffi-rzmq/lib/rigor/plugin/ffi_rzmq.rb +1 -0
  374. data/plugins/rigor-graphql/lib/rigor/plugin/graphql/type_scanner.rb +8 -6
  375. data/plugins/rigor-graphql/lib/rigor/plugin/graphql.rb +6 -3
  376. data/plugins/rigor-hanami/lib/rigor/plugin/hanami.rb +1 -0
  377. data/plugins/rigor-mangrove/lib/rigor/plugin/mangrove.rb +2 -1
  378. data/plugins/rigor-minitest/lib/rigor/plugin/minitest/assertion_analyzer.rb +0 -3
  379. data/plugins/rigor-minitest/lib/rigor/plugin/minitest.rb +1 -0
  380. data/plugins/rigor-pundit/lib/rigor/plugin/pundit/analyzer.rb +0 -5
  381. data/plugins/rigor-pundit/lib/rigor/plugin/pundit/authorization_scan.rb +2 -2
  382. data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_discoverer.rb +0 -1
  383. data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_index.rb +0 -1
  384. data/plugins/rigor-pundit/lib/rigor/plugin/pundit.rb +1 -0
  385. data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/analyzer.rb +0 -12
  386. data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_index.rb +1 -3
  387. data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_loader.rb +0 -1
  388. data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n.rb +1 -0
  389. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/acronyms.rb +5 -5
  390. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/analyzer.rb +1 -10
  391. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/devise_routes.rb +3 -3
  392. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/doorkeeper_routes.rb +2 -2
  393. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/grape_api_discoverer.rb +2 -2
  394. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_discoverer.rb +2 -2
  395. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_table.rb +9 -10
  396. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/routes_parser.rb +2 -3
  397. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes.rb +1 -0
  398. data/plugins/rigor-railties/lib/rigor/plugin/railties.rb +1 -0
  399. data/plugins/rigor-rbnacl/lib/rigor/plugin/rbnacl.rb +13 -1
  400. data/plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline.rb +128 -3
  401. data/plugins/rigor-rspec/lib/rigor/plugin/rspec/analyzer.rb +0 -3
  402. data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_scope_index.rb +0 -3
  403. data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_type_resolver.rb +1 -5
  404. data/plugins/rigor-rspec/lib/rigor/plugin/rspec/matcher_analyzer.rb +2 -3
  405. data/plugins/rigor-rspec/lib/rigor/plugin/rspec.rb +1 -0
  406. data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails/have_http_status_analyzer.rb +0 -3
  407. data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails.rb +1 -0
  408. data/plugins/rigor-sassc/lib/rigor/plugin/sassc.rb +1 -0
  409. data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers/analyzer.rb +1 -9
  410. data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers.rb +1 -0
  411. data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/analyzer.rb +0 -4
  412. data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/effects.rb +1 -1
  413. data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/schedule_scan.rb +1 -1
  414. data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_discoverer.rb +0 -1
  415. data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_index.rb +0 -2
  416. data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq.rb +1 -0
  417. data/plugins/rigor-sinatra/lib/rigor/plugin/sinatra.rb +1 -0
  418. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/absurd_recognizer.rb +2 -5
  419. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/assertion_recognizer.rb +1 -4
  420. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog.rb +3 -9
  421. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog_walker.rb +4 -4
  422. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sig_parser.rb +1 -2
  423. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sigil_detector.rb +4 -5
  424. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/type_translator.rb +7 -5
  425. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet.rb +5 -5
  426. data/plugins/rigor-statesman/lib/rigor/plugin/statesman.rb +1 -0
  427. data/sig/rigor/analysis/reachability/scan_cache.rbs +12 -0
  428. data/sig/rigor/cache.rbs +2 -3
  429. data/sig/rigor/environment.rbs +11 -0
  430. data/sig/rigor/inference.rbs +3 -10
  431. data/sig/rigor/plugin/io_boundary.rbs +4 -0
  432. data/sig/rigor/plugin/manifest.rbs +2 -1
  433. data/sig/rigor/reflection.rbs +3 -1
  434. data/sig/rigor/scope.rbs +24 -3
  435. data/sig/rigor/sig_gen/skip_reason_catalog.rbs +14 -0
  436. data/sig/rigor/type.rbs +27 -1
  437. data/sig/rigor.rbs +1 -0
  438. data/skills/rigor-ask/SKILL.md +8 -6
  439. data/skills/rigor-plugin-author/references/02-walker-and-types.md +13 -2
  440. data/skills/rigor-project-init/SKILL.md +6 -3
  441. data/skills/rigor-project-init/references/02-configure.md +10 -6
  442. data/skills/rigor-project-init/references/06-agent-contract.md +67 -0
  443. data/skills/rigor-type-oracle/SKILL.md +228 -0
  444. data/skills/rigor-type-oracle/references/01-oracle-commands.md +261 -0
  445. data/skills/rigor-type-oracle/references/02-agents-md-fragment.md +52 -0
  446. data/skills/rigor-type-oracle/references/03-gap-protocol.md +128 -0
  447. data/skills/rigor-unused-adjudicate/SKILL.md +8 -5
  448. metadata +28 -3
  449. data/lib/rigor/cli/probe_environment.rb +0 -85
  450. data/sig/rigor/inference/builtins/numeric_catalog.rbs +0 -3
@@ -117,6 +117,16 @@ module Rigor
117
117
  # `"stat"` (or `RIGOR_CI_DETECT=0`).
118
118
  "validation" => "auto"
119
119
  },
120
+ # ADR-39 slice 5 / #911 — the plugin-isolation strategy for target-library invocation. `nil` (the
121
+ # default) names nothing, leaving the choice to `RIGOR_PLUGIN_ISOLATION` and then to
122
+ # `Plugin::Isolation::DEFAULT`. The environment variable WINS over this key: it is the
123
+ # one-invocation operator override (`RIGOR_PLUGIN_ISOLATION=none rigor check` on a platform where
124
+ # the fork worker misbehaves), and an override a committed file can veto is not an override.
125
+ # Only `none` and `process` are selectable here — `ruby_box` needs `RUBY_BOX=1` set before Ruby
126
+ # boots, which is what `exe/rigor` re-execs for, and the launcher deliberately does not parse YAML
127
+ # before that re-exec (ADR-87 / ADR-104 boot-slim), so naming it here raises instead of silently
128
+ # resolving to a different strategy.
129
+ "plugins_isolation" => nil,
120
130
  "plugins_io" => {
121
131
  "network" => "disabled",
122
132
  "allowed_paths" => [],
@@ -212,6 +222,10 @@ module Rigor
212
222
  # reservation FINDABLE by the next person adding config validation (#166 is exactly that), and to
213
223
  # give the schema-parity spec something to key on: a reserved namespace is by definition absent
214
224
  # from DEFAULTS, so the DEFAULTS-driven schema gate can never see it.
225
+ # The isolation strategies a `.rigor.yml` may name (ADR-39 slice 5 / #911). `ruby_box` is
226
+ # deliberately absent: it is a boot-time decision the config file is read too late to make.
227
+ CONFIGURABLE_PLUGIN_ISOLATIONS = %w[none process].freeze
228
+
215
229
  RESERVED_NAMESPACES = %w[rigor_rs].freeze
216
230
 
217
231
  # Every top-level key a conforming `.rigor.yml` may carry: the keys this implementation owns, plus
@@ -238,6 +252,7 @@ module Rigor
238
252
  attr_reader :target_ruby, :paths, :exclude_patterns, :plugins, :cache_path, :cache_max_bytes,
239
253
  :cache_validation, :disabled_rules,
240
254
  :libraries, :signature_paths, :fold_platform_specific_paths, :parameter_inference,
255
+ :plugins_isolation,
241
256
  :plugins_io_network, :plugins_io_allowed_paths,
242
257
  :plugins_io_allowed_url_hosts,
243
258
  :severity_profile, :severity_overrides,
@@ -466,7 +481,7 @@ module Rigor
466
481
 
467
482
  # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
468
483
  #
469
- # @param effects_key_present [Boolean] ADR-103 WD15 — whether the file this `data` came from carried an
484
+ # @param effects_key_present — ADR-103 WD15 — whether the file this `data` came from carried an
470
485
  # `effects:` key at all, independent of its value. Defaults to `data.key?("effects")`, which is the
471
486
  # right answer for a caller that passes a raw (non-`DEFAULTS`-merged) hash directly — the common shape
472
487
  # in specs — but is always `true` once `data` has been through `DEFAULTS.merge`, because `DEFAULTS`
@@ -520,6 +535,9 @@ module Rigor
520
535
  raw_max = cache.fetch("max_bytes")
521
536
  @cache_max_bytes = raw_max.nil? ? nil : Integer(raw_max)
522
537
  @cache_validation = coerce_cache_validation(cache.fetch("validation", "auto"))
538
+ @plugins_isolation = coerce_plugins_isolation(
539
+ data.fetch("plugins_isolation", DEFAULTS.fetch("plugins_isolation"))
540
+ )
523
541
  @plugins_io_network = coerce_network_policy(plugins_io.fetch("network"))
524
542
  @plugins_io_allowed_paths = Array(plugins_io.fetch("allowed_paths")).map(&:to_s).freeze
525
543
  @plugins_io_allowed_url_hosts = Array(plugins_io.fetch("allowed_url_hosts")).map(&:to_s).freeze
@@ -583,6 +601,7 @@ module Rigor
583
601
  "max_bytes" => cache_max_bytes,
584
602
  "validation" => cache_validation
585
603
  },
604
+ "plugins_isolation" => plugins_isolation,
586
605
  "plugins_io" => {
587
606
  "network" => plugins_io_network.to_s,
588
607
  "allowed_paths" => plugins_io_allowed_paths,
@@ -626,9 +645,8 @@ module Rigor
626
645
  # the same checkout: a typo is a bug, and reading it as `false` would ship the feature permanently off
627
646
  # with no signal.
628
647
  #
629
- # @param id [String] a feature id from {BleedingEdge::FEATURES} or {BleedingEdge::GRADUATED}.
630
- # @return [Boolean]
631
- # @raise [ArgumentError] if `id` names no known feature.
648
+ # @param id — a feature id from {BleedingEdge::FEATURES} or {BleedingEdge::GRADUATED}.
649
+ # @raise ArgumentError — if `id` names no known feature.
632
650
  def bleeding_edge_active?(id)
633
651
  return true if BleedingEdge.graduated?(id)
634
652
  unless BleedingEdge.known_id?(id)
@@ -967,6 +985,27 @@ module Rigor
967
985
  VALID_CACHE_VALIDATIONS.include?(str) ? str : "auto"
968
986
  end
969
987
 
988
+ # Rejects rather than fails soft — a strategy that silently resolves to a different one is exactly
989
+ # the failure #911 exists to close, and the run's isolation is not a detail the user can be assumed
990
+ # not to have meant.
991
+ def coerce_plugins_isolation(value)
992
+ return nil if value.nil?
993
+
994
+ str = value.to_s
995
+ return str if CONFIGURABLE_PLUGIN_ISOLATIONS.include?(str)
996
+
997
+ if str == "ruby_box"
998
+ raise ConfigurationError,
999
+ "plugins_isolation: ruby_box cannot be selected from the configuration file — `Ruby::Box` " \
1000
+ "must be active before Ruby boots. Run rigor with RIGOR_PLUGIN_ISOLATION=ruby_box instead " \
1001
+ "(the launcher re-execs itself with RUBY_BOX=1 set)."
1002
+ end
1003
+
1004
+ raise ConfigurationError,
1005
+ "plugins_isolation must be one of #{CONFIGURABLE_PLUGIN_ISOLATIONS.inspect} " \
1006
+ "(`ruby_box` is environment-only), got #{value.inspect}"
1007
+ end
1008
+
970
1009
  def coerce_network_policy(value)
971
1010
  sym = value.to_sym
972
1011
  unless VALID_NETWORK_POLICIES.include?(sym)
@@ -30,7 +30,7 @@ module Rigor
30
30
  @empty ||= new({})
31
31
  end
32
32
 
33
- # @param table [Hash{String => Array<String>}] `Configuration#effects_attribution` — method key to
33
+ # @param table — `Configuration#effects_attribution` — method key to
34
34
  # label list, both already shape-validated at load (tier 2).
35
35
  def self.build(table)
36
36
  return empty if table.nil? || table.empty?
@@ -49,8 +49,6 @@ module Rigor
49
49
 
50
50
  # The labels attributed to a method key (`Net::HTTP.get`), or nil when the table says nothing about
51
51
  # it. The key is spelled by the caller, which already builds the same string for the catalogue.
52
- #
53
- # @return [LabelSet, nil]
54
52
  def [](key)
55
53
  @rows[key]
56
54
  end
@@ -69,9 +69,8 @@ module Rigor
69
69
 
70
70
  # Resolves `Configuration#effects_envelopes` against a registry.
71
71
  #
72
- # @param entries [Array<Hash>] the loaded, shape-validated entries
73
- # @param registry [Registry] the vocabulary, project extensions included
74
- # @return [Array<Entry>]
72
+ # @param entries — the loaded, shape-validated entries
73
+ # @param registry — the vocabulary, project extensions included
75
74
  def build(entries:, registry:)
76
75
  entries.each_with_index.map do |entry, index|
77
76
  labels = Array(entry["effect"]).map(&:to_s)
@@ -86,11 +85,10 @@ module Rigor
86
85
 
87
86
  # The class-level envelopes the entries put on a project.
88
87
  #
89
- # @param entries [Array<Entry>]
90
- # @param class_names [Enumerable<String>] every class the run collected units for
91
- # @param sources [Hash{String => Array<String>}] `Runner#effect_sources` — `{method key => [path]}`
92
- # @param project_root [String] what `sources` paths are relativised against
93
- # @return [Hash{String => Envelope}] one envelope per selected class, keyed by class name
88
+ # @param class_names — every class the run collected units for
89
+ # @param sources — `Runner#effect_sources` — `{method key => [path]}`
90
+ # @param project_root — what `sources` paths are relativised against
91
+ # @return one envelope per selected class, keyed by class name
94
92
  def for_classes(entries:, class_names:, sources: {}, project_root: Dir.pwd)
95
93
  return NO_ENVELOPES if entries.empty?
96
94
 
@@ -3,6 +3,7 @@
3
3
  require "prism"
4
4
 
5
5
  require_relative "method_key"
6
+ require_relative "../source/constant_path"
6
7
 
7
8
  module Rigor
8
9
  module Effects
@@ -30,9 +31,9 @@ module Rigor
30
31
  NO_LINES = {}.freeze
31
32
  private_constant :NO_LINES
32
33
 
33
- # @param key [String] an effect unit key — `Tracer::Loud#emit`, `Net::HTTP.get`.
34
- # @param path [String] the file the key was traced to.
35
- # @return [Integer, nil] the `def`'s line, or nil when this file does not spell that key with a
34
+ # @param key — an effect unit key — `Tracer::Loud#emit`, `Net::HTTP.get`.
35
+ # @param path — the file the key was traced to.
36
+ # @return the `def`'s line, or nil when this file does not spell that key with a
36
37
  # `def` — an unreadable file, a syntax error, and a synthesized method all land here.
37
38
  def for(key:, path:)
38
39
  index_for(path)[key]
@@ -62,10 +63,10 @@ module Rigor
62
63
  def walk(node, nesting, singleton:, index:)
63
64
  case node
64
65
  when Prism::ModuleNode, Prism::ClassNode
65
- name = constant_name(node.constant_path)
66
- return if name.nil?
66
+ inner = header_nesting(nesting, node.constant_path)
67
+ return if inner.nil?
67
68
 
68
- walk_children(node.body, nesting + [name], singleton: false, index: index)
69
+ walk_children(node.body, inner, singleton: false, index: index)
69
70
  when Prism::SingletonClassNode
70
71
  walk_children(node.body, nesting, singleton: true, index: index)
71
72
  when Prism::DefNode
@@ -76,6 +77,24 @@ module Rigor
76
77
  end
77
78
  end
78
79
 
80
+ # A ROOTED header is the one case that needs no resolution to place: `::` re-anchors the declaration at
81
+ # the top level wherever it is written, exactly as `Source::ConstantPath.declaration_prefix` reads it
82
+ # for the engine's own walks. Prism's `full_name` KEEPS the `::`, so `class ::Rooted` inside
83
+ # `module Outer` was indexed under `Outer::::Rooted#m` — a key no caller spells, which cost the row
84
+ # its line while every unrooted sibling in the same file kept one
85
+ # ([#722](https://github.com/rigortype/rigor/issues/722) residue 4).
86
+ #
87
+ # nil propagates the refusal {#constant_name} makes, so a header naming no constant leaves the subtree
88
+ # unindexed rather than under a guessed name.
89
+ def header_nesting(nesting, constant_path)
90
+ name = constant_name(constant_path)
91
+ return nil if name.nil?
92
+
93
+ return nesting + [name] unless Source::ConstantPath.rooted?(constant_path)
94
+
95
+ [name.delete_prefix("::")]
96
+ end
97
+
79
98
  def walk_children(node, nesting, singleton:, index:)
80
99
  node&.compact_child_nodes&.each { |child| walk(child, nesting, singleton: singleton, index: index) }
81
100
  end
@@ -61,7 +61,6 @@ module Rigor
61
61
  @empty ||= new(EMPTY_ENTRIES)
62
62
  end
63
63
 
64
- # @param entries [Hash{String => Entry}]
65
64
  def initialize(entries)
66
65
  @entries = entries.sort_by { |key, _| key }.to_h.freeze
67
66
  freeze
@@ -117,8 +117,6 @@ module Rigor
117
117
  # one message: the unregistered-preset error (#433) and the note `rigor effects update` prints
118
118
  # when `reach:` is empty (#436) have to give the same answer, and neither can hard-code a list
119
119
  # that moves with `plugins:`.
120
- #
121
- # @return [String]
122
120
  def availability
123
121
  if @presets.empty?
124
122
  return "no plugin in this project registers an entry-point preset — a preset is named by the " \
@@ -61,7 +61,7 @@ module Rigor
61
61
  # It lives on the value rather than in {EnvelopeCheck} because {LiskovCheck} positions its
62
62
  # findings identically, and two spellings of "where the fix goes" would eventually disagree.
63
63
  #
64
- # @return [Array(String, Integer)] `[path, line]`; `[nil, 1]` for a key with no owner.
64
+ # @return `[path, line]`; `[nil, 1]` for a key with no owner.
65
65
  def for(key)
66
66
  class_name, separator, selector = MethodKey.split(key)
67
67
  return [nil, 1] if class_name.nil?
@@ -103,17 +103,17 @@ module Rigor
103
103
 
104
104
  module_function
105
105
 
106
- # @param table [EffectTable] the run's propagated graph.
107
- # @param method_envelopes [Hash{String => Envelope}] per-method envelopes, as written.
108
- # @param class_envelopes [Hash{String => Envelope}] class- / module-level envelopes, to distribute.
109
- # @param config_envelopes [Hash{String => Envelope}] `effects.envelopes:` entries already resolved
106
+ # @param table — the run's propagated graph.
107
+ # @param method_envelopes — per-method envelopes, as written.
108
+ # @param class_envelopes — class- / module-level envelopes, to distribute.
109
+ # @param config_envelopes — `effects.envelopes:` entries already resolved
110
110
  # to the classes they select ({ConfigEnvelopes.for_classes}), to distribute at the lowest precedence.
111
- # @param positions [Positions, DeferredPositions] the discovery tables a finding's `def`
111
+ # @param positions — the discovery tables a finding's `def`
112
112
  # position is read from — consulted only when a finding is built, so a deferred value's
113
113
  # discovery force is reached exactly as often as a finding exists.
114
- # @param apply_tolerated [Boolean] false judges against the undischarged-by-policy `proven` lane —
114
+ # @param apply_tolerated — false judges against the undischarged-by-policy `proven` lane —
115
115
  # the `--no-tolerated-effects` audit switch.
116
- # @return [Array<Finding>] sorted by position then key then label, so a run explains identically twice.
116
+ # @return sorted by position then key then label, so a run explains identically twice.
117
117
  def run(table:, method_envelopes:, class_envelopes:, config_envelopes: {},
118
118
  positions: Positions.empty, apply_tolerated: true)
119
119
  envelopes = distribute(table, method_envelopes, class_envelopes, config_envelopes)
@@ -56,15 +56,13 @@ module Rigor
56
56
 
57
57
  # Reads every stratum this index serves, once per process.
58
58
  #
59
- # @param configuration [Rigor::Configuration]
60
- # @param plugin_facts [Rigor::Effects::PluginFacts, nil] the loaded plugins' effect contributions
59
+ # @param plugin_facts — the loaded plugins' effect contributions
61
60
  # (#387); their `effect_labels:` join the vocabulary an annotation is read against, so a gem's
62
61
  # `%a{rigor:v1:effect rails.activejob.enqueue}` resolves rather than reading as unknown.
63
- # @param environment [Rigor::Environment, nil] the run's environment. Its loader supplies the
62
+ # @param environment — the run's environment. Its loader supplies the
64
63
  # rbs-inline / plugin `virtual_rbs` buffers and the built RBS environment the accepted stratum is
65
64
  # read from; without one, both are simply absent (the fail-quiet direction — a missing `≤` bound
66
65
  # costs precision, never a finding).
67
- # @return [EnvelopeIndex]
68
66
  def self.build(configuration:, environment: nil, plugin_facts: nil)
69
67
  # Required here rather than at the top of the file: the reader pulls in the whole
70
68
  # `RbsExtended` surface, and this build runs only under an `effects:` block.
@@ -122,10 +120,9 @@ module Rigor
122
120
 
123
121
  # The envelope bounding `owner`'s `selector`, or nil.
124
122
  #
125
- # @param owner [String] the receiver's static class name, as the typer projected it
126
- # @param singleton [Boolean] whether the call is `Owner.selector` rather than `Owner#selector`
127
- # @param selector [String]
128
- # @return [Envelope, nil] never a ⊤ envelope: a bound that bounds nothing is not a bound, and
123
+ # @param owner — the receiver's static class name, as the typer projected it
124
+ # @param singleton — whether the call is `Owner.selector` rather than `Owner#selector`
125
+ # @return never a ⊤ envelope: a bound that bounds nothing is not a bound, and
129
126
  # importing it would both add nothing and discharge a taint on the strength of a typo.
130
127
  def [](owner, singleton, selector)
131
128
  return nil if owner.nil? || empty?
@@ -76,13 +76,11 @@ module Rigor
76
76
 
77
77
  # Every synthetic unit `class_name` earns, as `[key, Summary, edges]` triples.
78
78
  #
79
- # @param class_name [String]
80
- # @param instance_methods [Array<String>] the instance methods the class body defines, in source order
81
- # @param macros [Hash{String=>Array<String>}] receiver-less class-body calls to their literal symbol
79
+ # @param instance_methods — the instance methods the class body defines, in source order
80
+ # @param macros — receiver-less class-body calls to their literal symbol
82
81
  # arguments, as the scanner harvested them
83
- # @param uniqueness [Boolean] whether the class body declares a uniqueness validator
84
- # @param plugin_facts [PluginFacts]
85
- # @param own_units [Hash{String=>Boolean}] the units the class body itself defines, keyed by the
82
+ # @param uniqueness — whether the class body declares a uniqueness validator
83
+ # @param own_units — the units the class body itself defines, keyed by the
86
84
  # suffix a synthetic key carries (`"#save"`, `".create"`), each mapped to whether that body
87
85
  # reaches `super`. Read by {.framework_row} and by nothing else.
88
86
  def synthesize(class_name:, instance_methods:, macros:, uniqueness:, plugin_facts:, own_units: {})
@@ -45,10 +45,9 @@ module Rigor
45
45
  # The effects identity as a hex digest — the form a store with no descriptor of its own (the ADR-46
46
46
  # incremental snapshot) carries alongside its payload, and compares verbatim on restore.
47
47
  #
48
- # @param configuration [Rigor::Configuration]
49
- # @param registry [Registry] the vocabulary whose version participates
50
- # @param catalog [Catalog] the catalogue whose identity participates
51
- # @return [String] hex SHA-256
48
+ # @param registry — the vocabulary whose version participates
49
+ # @param catalog — the catalogue whose identity participates
50
+ # @return hex SHA-256
52
51
  def digest(configuration:, registry: Registry.default, catalog: Catalog.default, plugin_facts: nil)
53
52
  Digest::SHA256.hexdigest(
54
53
  [
@@ -66,8 +65,7 @@ module Rigor
66
65
  # the analyzed-path set — for free, so "the effects identity is the diagnostics identity plus three
67
66
  # things" is a property of the code rather than a claim about it.
68
67
  #
69
- # @param base [Cache::Descriptor] the run's diagnostics key descriptor
70
- # @return [Cache::Descriptor]
68
+ # @param base — the run's diagnostics key descriptor
71
69
  def descriptor(base:, configuration:, registry: Registry.default, catalog: Catalog.default,
72
70
  plugin_facts: nil)
73
71
  Cache::Descriptor.compose(
@@ -49,9 +49,9 @@ module Rigor
49
49
  SPELLING_PATTERN = /%a\{[^}]*\}/
50
50
  private_constant :SPELLING_PATTERN
51
51
 
52
- # @param path [String] the buffer's readable path, as {SignatureSources.source_path} renders it.
53
- # @param buffer [String] the synthesized RBS the position was read out of.
54
- # @return [InlineAnchor, nil] nil when `path` is not a Ruby file — a real `.rbs` needs no mapping,
52
+ # @param path — the buffer's readable path, as {SignatureSources.source_path} renders it.
53
+ # @param buffer — the synthesized RBS the position was read out of.
54
+ # @return nil when `path` is not a Ruby file — a real `.rbs` needs no mapping,
55
55
  # and its own line numbers are already the ones a reader can open.
56
56
  def self.for(path:, buffer:)
57
57
  return nil unless path.to_s.end_with?(RUBY_EXTENSION)
@@ -61,7 +61,7 @@ module Rigor
61
61
 
62
62
  # One-shot form, for a caller that holds a `[path, buffer, line]` triple and no anchor.
63
63
  #
64
- # @return [Integer] the `.rb` line, or `buffer_line` unchanged when there is nothing to map.
64
+ # @return the `.rb` line, or `buffer_line` unchanged when there is nothing to map.
65
65
  def self.ruby_line(path:, buffer:, buffer_line:, spelling: nil)
66
66
  anchor = self.for(path: path, buffer: buffer)
67
67
  return buffer_line if anchor.nil?
@@ -75,10 +75,10 @@ module Rigor
75
75
  @ruby_lines = nil
76
76
  end
77
77
 
78
- # @param buffer_line [Integer] 1-based, counting into the synthesized buffer.
79
- # @param spelling [String, nil] the annotation's own text (`"%a{pure}"`); read off the buffer line
78
+ # @param buffer_line — 1-based, counting into the synthesized buffer.
79
+ # @param spelling — the annotation's own text (`"%a{pure}"`); read off the buffer line
80
80
  # when the caller does not already hold it.
81
- # @return [Integer] the 1-based line of the same annotation in the Ruby file.
81
+ # @return the 1-based line of the same annotation in the Ruby file.
82
82
  def line_for(buffer_line, spelling: nil)
83
83
  spelling = normalize(spelling) || spelling_at(buffer_line)
84
84
  return buffer_line if spelling.nil?
@@ -37,11 +37,10 @@ module Rigor
37
37
 
38
38
  # Whether reporting `token` as an unknown label is justified.
39
39
  #
40
- # @param token [String] the spelling as written.
41
- # @param registry [Rigor::Effects::Registry, nil] the vocabulary AFTER plugin load; `nil` (no
40
+ # @param token — the spelling as written.
41
+ # @param registry — the vocabulary AFTER plugin load; `nil` (no
42
42
  # vocabulary at all) makes every token unjudgeable and therefore silent.
43
- # @param siblings [Array<String>] the other tokens of the same list / the same config value.
44
- # @return [Boolean]
43
+ # @param siblings — the other tokens of the same list / the same config value.
45
44
  def evident?(token, registry, siblings: [])
46
45
  return false if registry.nil?
47
46
  return false unless Label.valid?(token)
@@ -56,16 +56,16 @@ module Rigor
56
56
 
57
57
  module_function
58
58
 
59
- # @param table [EffectTable] the run's propagated graph.
60
- # @param superclasses [Hash{String => Array<String>}] the collector's as-written superclass
59
+ # @param table — the run's propagated graph.
60
+ # @param superclasses — the collector's as-written superclass
61
61
  # candidate lists (`FileCollection#superclasses`).
62
- # @param method_envelopes [Hash{String => Envelope}] per-method envelopes, as written.
63
- # @param class_envelopes [Hash{String => Envelope}] class- / module-level envelopes, to distribute.
64
- # @param config_envelopes [Hash{String => Envelope}] `effects.envelopes:` entries already resolved
62
+ # @param method_envelopes — per-method envelopes, as written.
63
+ # @param class_envelopes — class- / module-level envelopes, to distribute.
64
+ # @param config_envelopes — `effects.envelopes:` entries already resolved
65
65
  # to the classes they select.
66
- # @param positions [EnvelopeCheck::Positions] where the override's `def` is.
67
- # @param apply_tolerated [Boolean] false judges against `proven` — `--no-tolerated-effects`.
68
- # @return [Array<Finding>] sorted by position then key then label.
66
+ # @param positions — where the override's `def` is.
67
+ # @param apply_tolerated — false judges against `proven` — `--no-tolerated-effects`.
68
+ # @return sorted by position then key then label.
69
69
  def run(table:, superclasses:, method_envelopes:, class_envelopes:, config_envelopes: {},
70
70
  positions: EnvelopeCheck::Positions.empty, apply_tolerated: true)
71
71
  # The distributed strata, over a base of the raw per-method annotations: a base class whose method
@@ -14,7 +14,7 @@ module Rigor
14
14
  module MethodKey
15
15
  module_function
16
16
 
17
- # @return [Array(String, String, String), nil] `[owner, separator, selector]`, or nil when `key` is
17
+ # @return `[owner, separator, selector]`, or nil when `key` is
18
18
  # not a method key at all.
19
19
  def split(key)
20
20
  text = key.to_s
@@ -77,11 +77,10 @@ module Rigor
77
77
  @empty ||= new(contributions: [], superclasses: NO_ROWS, includes: NO_ROWS)
78
78
  end
79
79
 
80
- # @param plugin_registry [Rigor::Plugin::Registry, nil]
81
- # @param superclasses [Hash{String=>String,Array<String>}] the project's as-written superclass table
80
+ # @param superclasses — the project's as-written superclass table
82
81
  # (`Scope::DiscoveryIndex#discovered_superclasses`). Empty is legal and simply means no row matches
83
82
  # through inheritance.
84
- # @param includes [Hash{String=>Array<String>}] the project's as-written include / prepend table
83
+ # @param includes — the project's as-written include / prepend table
85
84
  # (`Scope::DiscoveryIndex#discovered_includes`), for the frameworks whose contract is a module
86
85
  # rather than a base class (#456).
87
86
  def self.build(plugin_registry, superclasses: NO_ROWS, includes: NO_ROWS)
@@ -144,9 +143,8 @@ module Rigor
144
143
 
145
144
  # The row colouring `owner`'s `selector`, found on `owner` itself or on a project ancestor of it.
146
145
  #
147
- # @param owner [String, nil] the receiver's class name as the syntax or the typer named it
148
- # @param singleton [Boolean] whether the call is `Owner.selector`
149
- # @return [Row, nil]
146
+ # @param owner — the receiver's class name as the syntax or the typer named it
147
+ # @param singleton — whether the call is `Owner.selector`
150
148
  def class_row(owner, singleton, selector)
151
149
  return nil if owner.nil? || @class_rows.empty?
152
150
 
@@ -45,10 +45,9 @@ module Rigor
45
45
 
46
46
  module_function
47
47
 
48
- # @param collection [FileCollection] the run's merged per-file collections
49
- # @param discharge [Discharge] the `effects.tolerated:` policy the undischarged lane is computed
48
+ # @param collection — the run's merged per-file collections
49
+ # @param discharge — the `effects.tolerated:` policy the undischarged lane is computed
50
50
  # under; {Discharge.none} makes the two lanes equal.
51
- # @return [EffectTable]
52
51
  def propagate(collection, discharge: Discharge.none)
53
52
  return EffectTable.empty if collection.summaries.empty?
54
53
 
@@ -184,7 +184,7 @@ module Rigor
184
184
  # per unit (ADR-103 WD13): a unit the scanner cannot finish is recorded as non-exhaustive with
185
185
  # `collector-error` and its siblings are unaffected.
186
186
  #
187
- # @return [UnitScan, nil] the finished scan, or nil when the unit failed soft
187
+ # @return the finished scan, or nil when the unit failed soft
188
188
  def add_unit(class_name, method_name, singleton, body, parameters)
189
189
  key = "#{class_name}#{singleton ? '.' : '#'}#{method_name}"
190
190
  names = parameter_names(parameters)
@@ -52,9 +52,8 @@ module Rigor
52
52
  stripped.start_with?(root) ? stripped[root.length..] : stripped
53
53
  end
54
54
 
55
- # @param signature_paths [Array<String>, nil] the configured roots; empty / nil takes the default.
56
- # @param virtual_rbs [Array<Array(String, String)>, nil] the loader's virtual entries.
57
- # @return [Array<Array(String, String)>]
55
+ # @param signature_paths — the configured roots; empty / nil takes the default.
56
+ # @param virtual_rbs — the loader's virtual entries.
58
57
  def collect(signature_paths:, virtual_rbs: nil)
59
58
  files = roots(signature_paths).flat_map { |root| Dir.glob(File.join(root.to_s, "**", "*.rbs")).sort }
60
59
  sources = files.filter_map do |path|
@@ -76,8 +75,7 @@ module Rigor
76
75
  # residual reports one annotation per run, so the carrier a run holds past the environment's own
77
76
  # lifetime is a single synthesized buffer rather than the project's whole virtual tree.
78
77
  #
79
- # @param virtual_rbs [Array<Array(String, String)>, nil]
80
- # @return [Array<Array(String, String)>] zero or one pair.
78
+ # @return zero or one pair.
81
79
  def annotated_carrier(virtual_rbs)
82
80
  Array(virtual_rbs).each do |name, content|
83
81
  return [[name.to_s, content.to_s]] if ANNOTATION_HINT.match?(content)
@@ -117,12 +117,12 @@ module Rigor
117
117
  class << self
118
118
  # Builds the snapshot a run's effect table describes.
119
119
  #
120
- # @param table [EffectTable] the propagated graph
121
- # @param configuration [Rigor::Configuration] supplies the reach globs and the digested block
122
- # @param sources [Hash{String=>Array<String>}] `Runner#effect_sources` — where each unit is defined
123
- # @param full [Boolean] keep the rows {#omit?} drops
124
- # @param registry [Registry] the vocabulary whose version the header carries
125
- # @param project_root [String] what `sources` paths are relativised against for glob matching
120
+ # @param table — the propagated graph
121
+ # @param configuration — supplies the reach globs and the digested block
122
+ # @param sources — `Runner#effect_sources` — where each unit is defined
123
+ # @param full — keep the rows {#omit?} drops
124
+ # @param registry — the vocabulary whose version the header carries
125
+ # @param project_root — what `sources` paths are relativised against for glob matching
126
126
  def build(table:, configuration:, sources: {}, full: false, registry: Registry.default,
127
127
  project_root: Dir.pwd)
128
128
  globs = expand_reach(configuration.effects_snapshot_reach)
@@ -146,10 +146,10 @@ module Rigor
146
146
  # It is built beside the snapshot and never inside it: the file stays flat and undischarged, and
147
147
  # this index exists only for the duration of one comparison ({SnapshotDiff}).
148
148
  #
149
- # @param snapshot [Snapshot] the current side, already built
150
- # @param table [EffectTable] the run that produced it
151
- # @param discharge [Discharge] the policy
152
- # @return [Hash, nil] nil when the policy discharges nothing, which is the common case
149
+ # @param snapshot — the current side, already built
150
+ # @param table — the run that produced it
151
+ # @param discharge — the policy
152
+ # @return nil when the policy discharges nothing, which is the common case
153
153
  def undischarged_index(snapshot:, table:, discharge:)
154
154
  return nil if discharge.inert?
155
155
 
@@ -86,7 +86,7 @@ module Rigor
86
86
  # Compares `current` against `recorded`. `recorded` may be nil — no snapshot on disk at all, which
87
87
  # is drift with a routed message rather than an error.
88
88
  #
89
- # @param undischarged [Hash] `{table name => {symbol => [label]}}` — the current side's labels that
89
+ # @param undischarged — `{table name => {symbol => [label]}}` — the current side's labels that
90
90
  # survive per-origin discharge ({Snapshot.undischarged_index}). Optional; omitting it judges every
91
91
  # event by label.
92
92
  def self.compare(recorded:, current:, tolerated: [], gate: :symmetric, strict_tolerated: false,
@@ -87,7 +87,7 @@ module Rigor
87
87
  # the enclosing method contains. A non-literal name has no key to file the block under, so it stays
88
88
  # contained in the enclosing method and this returns nil.
89
89
  #
90
- # @return [Array, nil] `[name, singleton, body, parameters]`
90
+ # @return `[name, singleton, body, parameters]`
91
91
  def self.define_method_unit(node)
92
92
  return nil unless node.name == :define_method && node.receiver.nil?
93
93
 
@@ -100,17 +100,17 @@ module Rigor
100
100
  [first.unescaped, false, block.body, block.parameters]
101
101
  end
102
102
 
103
- # @param singleton [Boolean] whether the unit's `self` is the class object (`def self.x`,
103
+ # @param singleton — whether the unit's `self` is the class object (`def self.x`,
104
104
  # `class << self`) — the axis that separates `mutate.self` from `mutate.static` on an ivar write
105
- # @param block_parameter [String, nil] the unit's `&blk` parameter name, if any; a call on it is
105
+ # @param block_parameter — the unit's `&blk` parameter name, if any; a call on it is
106
106
  # forwarding, not an opaque callable
107
- # @param calls [Hash] node-identity table of {Collector::CallRecord}s
108
- # @param attribution [Attribution] the project's `effects.attribution:` table
109
- # @param envelopes [EnvelopeIndex] the envelopes a call site may import as a `≤` bound (#386)
110
- # @param plugin_facts [PluginFacts] the loaded plugins' `effect_attributions:` (#387)
111
- # @param owner_class [String, nil] the class this unit is defined on — the carrier an
107
+ # @param calls — node-identity table of {Collector::CallRecord}s
108
+ # @param attribution — the project's `effects.attribution:` table
109
+ # @param envelopes — the envelopes a call site may import as a `≤` bound (#386)
110
+ # @param plugin_facts — the loaded plugins' `effect_attributions:` (#387)
111
+ # @param owner_class — the class this unit is defined on — the carrier an
112
112
  # implicit-self call's envelope is looked up under, since the syntax spells `Kernel#name`
113
- # @param method_name [String, nil] this unit's own selector — what a `super` in its body names as
113
+ # @param method_name — this unit's own selector — what a `super` in its body names as
114
114
  # the target the propagator resolves above `owner_class` (#446). With no name to state, a `super`
115
115
  # taints instead.
116
116
  def initialize(singleton:, parameters:, block_parameter:, owned_locals:, calls:, # rubocop:disable Metrics/ParameterLists
@@ -283,7 +283,7 @@ module Rigor
283
283
  # Three receiver shapes, tried nearest-syntax first — a written receiver path (`Rails.cache.read`),
284
284
  # a receiver rooted at implicit self inside a framework class (`session[:x] = 1`), and the receiver's
285
285
  # class through the project's inheritance chain (`user.save`).
286
- # @return [PluginFacts::Row, nil] the row that claimed this call, for {#visit_call} to read as a bound
286
+ # @return the row that claimed this call, for {#visit_call} to read as a bound
287
287
  def attribute_plugin(node, record)
288
288
  return nil unless @plugin_facts.attributions?
289
289
 
@@ -30,10 +30,6 @@ module Rigor
30
30
 
31
31
  module_function
32
32
 
33
- # @param method_envelopes [Hash{String => Envelope}]
34
- # @param class_envelopes [Hash{String => Envelope}]
35
- # @param registry [Rigor::Effects::Registry]
36
- # @return [Array<Finding>]
37
33
  def for_envelopes(method_envelopes:, class_envelopes:, registry:)
38
34
  seen = {}
39
35
  declarations(method_envelopes, class_envelopes).each do |envelope|
@@ -49,10 +45,9 @@ module Rigor
49
45
  seen.values
50
46
  end
51
47
 
52
- # @param labels [Array<String>] the list as written, in source order.
53
- # @param key_path [String] the `.rigor.yml` key, for the message (`effects.tolerated`).
54
- # @param consequence [String] what the degradation cost, for the message.
55
- # @return [Array<Finding>]
48
+ # @param labels — the list as written, in source order.
49
+ # @param key_path — the `.rigor.yml` key, for the message (`effects.tolerated`).
50
+ # @param consequence — what the degradation cost, for the message.
56
51
  def for_config(labels:, key_path:, consequence:, registry:)
57
52
  tokens = Array(labels).map(&:to_s)
58
53
  tokens.filter_map do |token|