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.
Files changed (414) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/docs/manual/04-diagnostics.md +7 -4
  4. data/docs/manual/06-baseline.md +5 -2
  5. data/docs/manual/15-type-protection-coverage.md +6 -4
  6. data/lib/rigor/analysis/baseline.rb +56 -96
  7. data/lib/rigor/analysis/buffer_binding.rb +13 -20
  8. data/lib/rigor/analysis/check_rules/always_truthy_condition_collector.rb +29 -48
  9. data/lib/rigor/analysis/check_rules/dead_assignment_collector.rb +35 -54
  10. data/lib/rigor/analysis/check_rules/ivar_write_collector.rb +23 -37
  11. data/lib/rigor/analysis/check_rules/main_pass_collector.rb +16 -23
  12. data/lib/rigor/analysis/check_rules/rule_walk.rb +48 -71
  13. data/lib/rigor/analysis/check_rules/self_closedness_scanner.rb +19 -28
  14. data/lib/rigor/analysis/check_rules/unreachable_clause_collector.rb +48 -67
  15. data/lib/rigor/analysis/check_rules.rb +174 -274
  16. data/lib/rigor/analysis/dependency_recorder.rb +26 -38
  17. data/lib/rigor/analysis/dependency_source_inference/boundary_cross_reporter.rb +13 -25
  18. data/lib/rigor/analysis/dependency_source_inference/builder.rb +17 -30
  19. data/lib/rigor/analysis/dependency_source_inference/gem_resolver.rb +15 -26
  20. data/lib/rigor/analysis/dependency_source_inference/index.rb +45 -76
  21. data/lib/rigor/analysis/dependency_source_inference/return_type_heuristic.rb +23 -40
  22. data/lib/rigor/analysis/dependency_source_inference/walker.rb +50 -83
  23. data/lib/rigor/analysis/dependency_source_inference.rb +6 -10
  24. data/lib/rigor/analysis/diagnostic.rb +48 -75
  25. data/lib/rigor/analysis/erb_template_detector.rb +13 -18
  26. data/lib/rigor/analysis/fact_store.rb +12 -22
  27. data/lib/rigor/analysis/incremental.rb +47 -63
  28. data/lib/rigor/analysis/incremental_session.rb +74 -100
  29. data/lib/rigor/analysis/project_scan.rb +12 -23
  30. data/lib/rigor/analysis/result.rb +3 -5
  31. data/lib/rigor/analysis/rule_catalog.rb +67 -95
  32. data/lib/rigor/analysis/run_stats.rb +38 -61
  33. data/lib/rigor/analysis/runner/diagnostic_aggregator.rb +101 -160
  34. data/lib/rigor/analysis/runner/pool_coordinator.rb +121 -188
  35. data/lib/rigor/analysis/runner/project_pre_passes.rb +62 -96
  36. data/lib/rigor/analysis/runner/run_snapshots.rb +12 -18
  37. data/lib/rigor/analysis/runner.rb +220 -333
  38. data/lib/rigor/analysis/self_call_resolution_recorder.rb +30 -43
  39. data/lib/rigor/analysis/worker_session.rb +64 -102
  40. data/lib/rigor/ast/type_node.rb +6 -8
  41. data/lib/rigor/ast.rb +6 -10
  42. data/lib/rigor/bleeding_edge.rb +27 -35
  43. data/lib/rigor/builtins/hkt_builtins.rb +7 -14
  44. data/lib/rigor/builtins/imported_refinements.rb +106 -149
  45. data/lib/rigor/builtins/predefined_constant_refinements.rb +51 -65
  46. data/lib/rigor/builtins/regex_refinement.rb +32 -43
  47. data/lib/rigor/builtins/static_return_refinements.rb +57 -81
  48. data/lib/rigor/cache/descriptor.rb +58 -94
  49. data/lib/rigor/cache/incremental_snapshot.rb +32 -48
  50. data/lib/rigor/cache/rbs_cache_producer.rb +10 -15
  51. data/lib/rigor/cache/rbs_class_ancestor_table.rb +10 -16
  52. data/lib/rigor/cache/rbs_class_type_param_names.rb +10 -16
  53. data/lib/rigor/cache/rbs_constant_table.rb +8 -13
  54. data/lib/rigor/cache/rbs_descriptor.rb +8 -13
  55. data/lib/rigor/cache/rbs_environment.rb +11 -19
  56. data/lib/rigor/cache/rbs_environment_marshal_patch.rb +11 -19
  57. data/lib/rigor/cache/rbs_known_class_names.rb +8 -12
  58. data/lib/rigor/cache/store.rb +96 -151
  59. data/lib/rigor/cli/annotate_command.rb +51 -88
  60. data/lib/rigor/cli/baseline_command.rb +10 -17
  61. data/lib/rigor/cli/check_command.rb +121 -199
  62. data/lib/rigor/cli/check_runner_factory.rb +8 -14
  63. data/lib/rigor/cli/ci_detector.rb +9 -14
  64. data/lib/rigor/cli/command.rb +8 -14
  65. data/lib/rigor/cli/coverage_command.rb +19 -26
  66. data/lib/rigor/cli/coverage_mutation.rb +14 -19
  67. data/lib/rigor/cli/coverage_report.rb +0 -2
  68. data/lib/rigor/cli/coverage_scan.rb +7 -11
  69. data/lib/rigor/cli/diagnostic_formats.rb +43 -62
  70. data/lib/rigor/cli/diff_command.rb +10 -20
  71. data/lib/rigor/cli/docs_command.rb +26 -40
  72. data/lib/rigor/cli/doctor_command.rb +8 -9
  73. data/lib/rigor/cli/explain_command.rb +4 -7
  74. data/lib/rigor/cli/fused_protection_renderer.rb +4 -5
  75. data/lib/rigor/cli/fused_protection_report.rb +6 -8
  76. data/lib/rigor/cli/lsp_command.rb +11 -19
  77. data/lib/rigor/cli/mcp_command.rb +4 -6
  78. data/lib/rigor/cli/mutation_protection_renderer.rb +3 -4
  79. data/lib/rigor/cli/mutation_protection_report.rb +6 -9
  80. data/lib/rigor/cli/options.rb +11 -19
  81. data/lib/rigor/cli/plugin_command.rb +18 -30
  82. data/lib/rigor/cli/plugins_command.rb +29 -51
  83. data/lib/rigor/cli/plugins_renderer.rb +12 -20
  84. data/lib/rigor/cli/prism_colorizer.rb +13 -19
  85. data/lib/rigor/cli/protection_renderer.rb +5 -7
  86. data/lib/rigor/cli/protection_report.rb +27 -17
  87. data/lib/rigor/cli/renderable.rb +4 -6
  88. data/lib/rigor/cli/show_bleedingedge_command.rb +5 -8
  89. data/lib/rigor/cli/sig_gen_command.rb +14 -26
  90. data/lib/rigor/cli/skill_command.rb +30 -47
  91. data/lib/rigor/cli/skill_describe.rb +40 -64
  92. data/lib/rigor/cli/trace_command.rb +9 -16
  93. data/lib/rigor/cli/trace_renderer.rb +35 -51
  94. data/lib/rigor/cli/triage_command.rb +6 -10
  95. data/lib/rigor/cli/triage_renderer.rb +1 -2
  96. data/lib/rigor/cli/type_of_command.rb +14 -23
  97. data/lib/rigor/cli/type_of_renderer.rb +3 -5
  98. data/lib/rigor/cli/type_scan_command.rb +6 -10
  99. data/lib/rigor/cli/type_scan_renderer.rb +3 -5
  100. data/lib/rigor/cli/type_scan_report.rb +2 -3
  101. data/lib/rigor/cli/upgrade_command.rb +2 -3
  102. data/lib/rigor/cli.rb +16 -28
  103. data/lib/rigor/config_audit.rb +35 -44
  104. data/lib/rigor/configuration/dependencies.rb +41 -70
  105. data/lib/rigor/configuration/severity_profile.rb +28 -42
  106. data/lib/rigor/configuration.rb +150 -241
  107. data/lib/rigor/environment/bundle_sig_discovery.rb +74 -118
  108. data/lib/rigor/environment/class_registry.rb +19 -26
  109. data/lib/rigor/environment/constant_type_cache_holder.rb +14 -21
  110. data/lib/rigor/environment/hkt_registry_holder.rb +6 -12
  111. data/lib/rigor/environment/lockfile_resolver.rb +31 -47
  112. data/lib/rigor/environment/rbs_collection_discovery.rb +39 -63
  113. data/lib/rigor/environment/rbs_coverage_report.rb +24 -42
  114. data/lib/rigor/environment/rbs_loader.rb +420 -518
  115. data/lib/rigor/environment/reflection.rb +28 -53
  116. data/lib/rigor/environment/reporters.rb +13 -24
  117. data/lib/rigor/environment.rb +176 -291
  118. data/lib/rigor/flow_contribution/conflict.rb +16 -27
  119. data/lib/rigor/flow_contribution/element.rb +7 -12
  120. data/lib/rigor/flow_contribution/fact.rb +33 -57
  121. data/lib/rigor/flow_contribution/merge_result.rb +6 -9
  122. data/lib/rigor/flow_contribution/merger.rb +32 -47
  123. data/lib/rigor/flow_contribution.rb +37 -55
  124. data/lib/rigor/inference/acceptance.rb +133 -219
  125. data/lib/rigor/inference/block_parameter_binder.rb +52 -82
  126. data/lib/rigor/inference/body_fixpoint.rb +22 -30
  127. data/lib/rigor/inference/budget_trace.rb +43 -63
  128. data/lib/rigor/inference/builtins/array_catalog.rb +4 -6
  129. data/lib/rigor/inference/builtins/comparable_catalog.rb +4 -6
  130. data/lib/rigor/inference/builtins/complex_catalog.rb +13 -19
  131. data/lib/rigor/inference/builtins/date_catalog.rb +38 -67
  132. data/lib/rigor/inference/builtins/encoding_catalog.rb +22 -36
  133. data/lib/rigor/inference/builtins/enumerable_catalog.rb +4 -6
  134. data/lib/rigor/inference/builtins/exception_catalog.rb +38 -57
  135. data/lib/rigor/inference/builtins/hash_catalog.rb +9 -14
  136. data/lib/rigor/inference/builtins/method_catalog.rb +29 -48
  137. data/lib/rigor/inference/builtins/numeric_catalog.rb +13 -18
  138. data/lib/rigor/inference/builtins/pathname_catalog.rb +8 -13
  139. data/lib/rigor/inference/builtins/proc_catalog.rb +38 -62
  140. data/lib/rigor/inference/builtins/random_catalog.rb +21 -32
  141. data/lib/rigor/inference/builtins/range_catalog.rb +12 -21
  142. data/lib/rigor/inference/builtins/rational_catalog.rb +9 -15
  143. data/lib/rigor/inference/builtins/re_catalog.rb +29 -48
  144. data/lib/rigor/inference/builtins/set_catalog.rb +18 -27
  145. data/lib/rigor/inference/builtins/string_catalog.rb +12 -19
  146. data/lib/rigor/inference/builtins/struct_catalog.rb +18 -30
  147. data/lib/rigor/inference/builtins/time_catalog.rb +28 -44
  148. data/lib/rigor/inference/closure_escape_analyzer.rb +44 -67
  149. data/lib/rigor/inference/coverage_scanner.rb +13 -18
  150. data/lib/rigor/inference/def_return_typer.rb +8 -14
  151. data/lib/rigor/inference/dynamic_origin.rb +23 -20
  152. data/lib/rigor/inference/expression_typer.rb +774 -1152
  153. data/lib/rigor/inference/fallback.rb +8 -12
  154. data/lib/rigor/inference/fallback_tracer.rb +4 -10
  155. data/lib/rigor/inference/flow_tracer.rb +25 -36
  156. data/lib/rigor/inference/hkt_body.rb +45 -68
  157. data/lib/rigor/inference/hkt_body_parser.rb +33 -52
  158. data/lib/rigor/inference/hkt_reducer.rb +38 -59
  159. data/lib/rigor/inference/hkt_registry.rb +50 -76
  160. data/lib/rigor/inference/indexed_narrowing.rb +55 -81
  161. data/lib/rigor/inference/macro_block_self_type.rb +21 -34
  162. data/lib/rigor/inference/method_dispatcher/array_to_h_folding.rb +11 -18
  163. data/lib/rigor/inference/method_dispatcher/block_folding.rb +49 -83
  164. data/lib/rigor/inference/method_dispatcher/call_context.rb +16 -23
  165. data/lib/rigor/inference/method_dispatcher/cgi_folding.rb +13 -22
  166. data/lib/rigor/inference/method_dispatcher/constant_folding.rb +307 -454
  167. data/lib/rigor/inference/method_dispatcher/data_folding.rb +24 -34
  168. data/lib/rigor/inference/method_dispatcher/file_folding.rb +22 -37
  169. data/lib/rigor/inference/method_dispatcher/iterator_dispatch.rb +52 -81
  170. data/lib/rigor/inference/method_dispatcher/kernel_dispatch.rb +51 -78
  171. data/lib/rigor/inference/method_dispatcher/literal_string_folding.rb +60 -97
  172. data/lib/rigor/inference/method_dispatcher/math_folding.rb +23 -34
  173. data/lib/rigor/inference/method_dispatcher/member_shape_projection.rb +18 -26
  174. data/lib/rigor/inference/method_dispatcher/method_folding.rb +37 -71
  175. data/lib/rigor/inference/method_dispatcher/overload_selector.rb +114 -182
  176. data/lib/rigor/inference/method_dispatcher/rbs_dispatch.rb +122 -193
  177. data/lib/rigor/inference/method_dispatcher/receiver_affinity.rb +15 -24
  178. data/lib/rigor/inference/method_dispatcher/reduce_folding.rb +64 -93
  179. data/lib/rigor/inference/method_dispatcher/regexp_folding.rb +31 -45
  180. data/lib/rigor/inference/method_dispatcher/set_folding.rb +6 -9
  181. data/lib/rigor/inference/method_dispatcher/shape_dispatch.rb +356 -511
  182. data/lib/rigor/inference/method_dispatcher/shellwords_folding.rb +22 -32
  183. data/lib/rigor/inference/method_dispatcher/singleton_folding.rb +15 -21
  184. data/lib/rigor/inference/method_dispatcher/struct_folding.rb +66 -82
  185. data/lib/rigor/inference/method_dispatcher/time_folding.rb +10 -15
  186. data/lib/rigor/inference/method_dispatcher/uri_folding.rb +9 -13
  187. data/lib/rigor/inference/method_dispatcher.rb +378 -524
  188. data/lib/rigor/inference/method_parameter_binder.rb +81 -114
  189. data/lib/rigor/inference/multi_target_binder.rb +51 -68
  190. data/lib/rigor/inference/mutation_widening.rb +115 -158
  191. data/lib/rigor/inference/narrowing.rb +509 -727
  192. data/lib/rigor/inference/origin_lookup.rb +38 -0
  193. data/lib/rigor/inference/parameter_inference_collector.rb +100 -100
  194. data/lib/rigor/inference/precision_scanner.rb +26 -35
  195. data/lib/rigor/inference/project_patched_methods.rb +20 -32
  196. data/lib/rigor/inference/project_patched_scanner.rb +23 -37
  197. data/lib/rigor/inference/protection_scanner.rb +16 -18
  198. data/lib/rigor/inference/rbs_type_translator.rb +49 -66
  199. data/lib/rigor/inference/scope_indexer.rb +473 -817
  200. data/lib/rigor/inference/statement_evaluator.rb +706 -1111
  201. data/lib/rigor/inference/struct_fold_safety.rb +34 -48
  202. data/lib/rigor/inference/synthetic_method.rb +9 -16
  203. data/lib/rigor/inference/synthetic_method_index.rb +20 -35
  204. data/lib/rigor/inference/synthetic_method_scanner.rb +63 -103
  205. data/lib/rigor/language_server/buffer_resolution.rb +6 -9
  206. data/lib/rigor/language_server/buffer_table.rb +11 -18
  207. data/lib/rigor/language_server/completion_provider.rb +69 -116
  208. data/lib/rigor/language_server/debouncer.rb +16 -25
  209. data/lib/rigor/language_server/diagnostic_publisher.rb +26 -40
  210. data/lib/rigor/language_server/document_symbol_provider.rb +14 -19
  211. data/lib/rigor/language_server/folding_range_provider.rb +11 -19
  212. data/lib/rigor/language_server/hover_provider.rb +8 -11
  213. data/lib/rigor/language_server/hover_renderer.rb +56 -93
  214. data/lib/rigor/language_server/loop.rb +14 -19
  215. data/lib/rigor/language_server/project_context.rb +46 -74
  216. data/lib/rigor/language_server/selection_range_provider.rb +9 -12
  217. data/lib/rigor/language_server/server.rb +55 -83
  218. data/lib/rigor/language_server/signature_help_provider.rb +29 -46
  219. data/lib/rigor/language_server/synchronized_writer.rb +4 -7
  220. data/lib/rigor/language_server/uri.rb +8 -13
  221. data/lib/rigor/language_server.rb +4 -6
  222. data/lib/rigor/mcp/loop.rb +2 -3
  223. data/lib/rigor/mcp/server.rb +4 -7
  224. data/lib/rigor/mcp.rb +3 -6
  225. data/lib/rigor/plugin/access_denied_error.rb +5 -8
  226. data/lib/rigor/plugin/additional_initializer.rb +21 -31
  227. data/lib/rigor/plugin/base.rb +335 -518
  228. data/lib/rigor/plugin/blueprint.rb +14 -23
  229. data/lib/rigor/plugin/box.rb +18 -29
  230. data/lib/rigor/plugin/fact_store.rb +16 -26
  231. data/lib/rigor/plugin/inflector.rb +37 -53
  232. data/lib/rigor/plugin/io_boundary.rb +33 -56
  233. data/lib/rigor/plugin/isolation.rb +42 -55
  234. data/lib/rigor/plugin/load_error.rb +10 -15
  235. data/lib/rigor/plugin/loader.rb +30 -49
  236. data/lib/rigor/plugin/macro/block_as_method.rb +20 -32
  237. data/lib/rigor/plugin/macro/heredoc_template.rb +35 -58
  238. data/lib/rigor/plugin/macro/nested_class_template.rb +22 -36
  239. data/lib/rigor/plugin/macro/trait_registry.rb +34 -51
  240. data/lib/rigor/plugin/macro.rb +10 -15
  241. data/lib/rigor/plugin/manifest.rb +85 -144
  242. data/lib/rigor/plugin/node_context.rb +14 -22
  243. data/lib/rigor/plugin/node_rule_walk.rb +49 -74
  244. data/lib/rigor/plugin/protocol_contract.rb +25 -39
  245. data/lib/rigor/plugin/registry.rb +132 -205
  246. data/lib/rigor/plugin/services.rb +21 -33
  247. data/lib/rigor/plugin/source_rbs_synthesis_reporter.rb +11 -19
  248. data/lib/rigor/plugin/trust_policy.rb +24 -38
  249. data/lib/rigor/plugin/type_node_resolver.rb +15 -24
  250. data/lib/rigor/protection/diagnostic_oracle.rb +11 -13
  251. data/lib/rigor/protection/mutation_scanner.rb +27 -35
  252. data/lib/rigor/protection/mutator.rb +50 -70
  253. data/lib/rigor/protection/test_suite_oracle.rb +20 -27
  254. data/lib/rigor/rbs_extended/conformance_checker.rb +48 -68
  255. data/lib/rigor/rbs_extended/hkt_directives.rb +28 -54
  256. data/lib/rigor/rbs_extended/reporter.rb +24 -40
  257. data/lib/rigor/rbs_extended.rb +107 -197
  258. data/lib/rigor/reflection.rb +68 -86
  259. data/lib/rigor/scope/discovery_index.rb +14 -19
  260. data/lib/rigor/scope.rb +255 -310
  261. data/lib/rigor/sig_gen/classification.rb +6 -10
  262. data/lib/rigor/sig_gen/generator.rb +197 -323
  263. data/lib/rigor/sig_gen/layout_index.rb +12 -20
  264. data/lib/rigor/sig_gen/method_candidate.rb +12 -17
  265. data/lib/rigor/sig_gen/observation_collector.rb +38 -70
  266. data/lib/rigor/sig_gen/observed_call.rb +13 -23
  267. data/lib/rigor/sig_gen/path_mapper.rb +17 -29
  268. data/lib/rigor/sig_gen/renderer.rb +7 -13
  269. data/lib/rigor/sig_gen/type_elaborator.rb +15 -28
  270. data/lib/rigor/sig_gen/write_result.rb +8 -16
  271. data/lib/rigor/sig_gen/writer.rb +95 -174
  272. data/lib/rigor/sig_gen.rb +3 -6
  273. data/lib/rigor/signature_path_audit.rb +24 -30
  274. data/lib/rigor/source/constant_path.rb +10 -14
  275. data/lib/rigor/source/literals.rb +31 -45
  276. data/lib/rigor/source/node_locator.rb +9 -11
  277. data/lib/rigor/source/node_walker.rb +9 -13
  278. data/lib/rigor/source.rb +3 -4
  279. data/lib/rigor/testing.rb +16 -20
  280. data/lib/rigor/triage/catalogue.rb +38 -62
  281. data/lib/rigor/triage.rb +31 -52
  282. data/lib/rigor/trinary.rb +9 -13
  283. data/lib/rigor/type/acceptance_router.rb +4 -6
  284. data/lib/rigor/type/accepts_result.rb +10 -14
  285. data/lib/rigor/type/app.rb +19 -27
  286. data/lib/rigor/type/bot.rb +4 -6
  287. data/lib/rigor/type/bound_method.rb +10 -15
  288. data/lib/rigor/type/combinator.rb +165 -257
  289. data/lib/rigor/type/constant.rb +23 -34
  290. data/lib/rigor/type/data_class.rb +10 -15
  291. data/lib/rigor/type/data_instance.rb +14 -20
  292. data/lib/rigor/type/difference.rb +21 -32
  293. data/lib/rigor/type/dynamic.rb +3 -5
  294. data/lib/rigor/type/hash_shape.rb +32 -18
  295. data/lib/rigor/type/integer_range.rb +11 -16
  296. data/lib/rigor/type/intersection.rb +27 -42
  297. data/lib/rigor/type/nominal.rb +10 -15
  298. data/lib/rigor/type/plain_lattice.rb +9 -13
  299. data/lib/rigor/type/refined.rb +67 -114
  300. data/lib/rigor/type/singleton.rb +4 -6
  301. data/lib/rigor/type/struct_class.rb +11 -16
  302. data/lib/rigor/type/struct_instance.rb +15 -21
  303. data/lib/rigor/type/tuple.rb +14 -19
  304. data/lib/rigor/type/union.rb +30 -42
  305. data/lib/rigor/type_node/generic.rb +14 -26
  306. data/lib/rigor/type_node/identifier.rb +12 -19
  307. data/lib/rigor/type_node.rb +3 -12
  308. data/lib/rigor/value_semantics.rb +16 -21
  309. data/lib/rigor/version.rb +1 -1
  310. data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/analyzer.rb +18 -30
  311. data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_discoverer.rb +16 -29
  312. data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_index.rb +12 -23
  313. data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable.rb +22 -39
  314. data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/analyzer.rb +26 -46
  315. data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_discoverer.rb +51 -87
  316. data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_index.rb +10 -17
  317. data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer.rb +26 -39
  318. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/analyzer.rb +118 -176
  319. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_discoverer.rb +30 -51
  320. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_index.rb +57 -92
  321. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack.rb +71 -108
  322. data/plugins/rigor-activejob/lib/rigor/plugin/activejob/analyzer.rb +13 -22
  323. data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_discoverer.rb +15 -25
  324. data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_index.rb +8 -13
  325. data/plugins/rigor-activejob/lib/rigor/plugin/activejob.rb +16 -24
  326. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/analyzer.rb +30 -47
  327. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_discoverer.rb +79 -129
  328. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_index.rb +36 -57
  329. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_parser.rb +27 -41
  330. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_table.rb +16 -24
  331. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord.rb +148 -235
  332. data/plugins/rigor-activerecord/lib/rigor-activerecord.rb +3 -5
  333. data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/analyzer.rb +8 -14
  334. data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/attachment_discoverer.rb +9 -15
  335. data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/attachment_index.rb +4 -7
  336. data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage.rb +23 -41
  337. data/plugins/rigor-activestorage/lib/rigor-activestorage.rb +3 -5
  338. data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext.rb +6 -10
  339. data/plugins/rigor-activesupport-core-ext/lib/rigor-activesupport-core-ext.rb +8 -11
  340. data/plugins/rigor-devise/lib/rigor/plugin/devise.rb +30 -45
  341. data/plugins/rigor-devise/lib/rigor-devise.rb +3 -5
  342. data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema/schema_scanner.rb +43 -69
  343. data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema.rb +26 -35
  344. data/plugins/rigor-dry-schema/lib/rigor-dry-schema.rb +3 -5
  345. data/plugins/rigor-dry-struct/lib/rigor/plugin/dry_struct.rb +30 -47
  346. data/plugins/rigor-dry-struct/lib/rigor-dry-struct.rb +3 -5
  347. data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types/alias_scanner.rb +67 -113
  348. data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types.rb +29 -46
  349. data/plugins/rigor-dry-types/lib/rigor-dry-types.rb +3 -5
  350. data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation/contract_scanner.rb +13 -20
  351. data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation.rb +14 -23
  352. data/plugins/rigor-dry-validation/lib/rigor-dry-validation.rb +2 -3
  353. data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/analyzer.rb +22 -37
  354. data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_discoverer.rb +28 -46
  355. data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_index.rb +13 -17
  356. data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot.rb +30 -47
  357. data/plugins/rigor-graphql/lib/rigor/plugin/graphql/type_scanner.rb +52 -80
  358. data/plugins/rigor-graphql/lib/rigor/plugin/graphql.rb +21 -31
  359. data/plugins/rigor-graphql/lib/rigor-graphql.rb +3 -5
  360. data/plugins/rigor-hanami/lib/rigor/plugin/hanami/action_checker.rb +11 -17
  361. data/plugins/rigor-hanami/lib/rigor/plugin/hanami.rb +20 -34
  362. data/plugins/rigor-mangrove/lib/rigor/plugin/mangrove.rb +45 -75
  363. data/plugins/rigor-minitest/lib/rigor/plugin/minitest/assertion_analyzer.rb +22 -36
  364. data/plugins/rigor-minitest/lib/rigor/plugin/minitest.rb +22 -41
  365. data/plugins/rigor-pundit/lib/rigor/plugin/pundit/analyzer.rb +17 -32
  366. data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_discoverer.rb +6 -12
  367. data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_index.rb +4 -8
  368. data/plugins/rigor-pundit/lib/rigor/plugin/pundit.rb +17 -32
  369. data/plugins/rigor-rails/lib/rigor-rails.rb +11 -18
  370. data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/analyzer.rb +58 -92
  371. data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_index.rb +20 -34
  372. data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_loader.rb +20 -31
  373. data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n.rb +49 -82
  374. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/analyzer.rb +55 -92
  375. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/devise_routes.rb +51 -90
  376. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/doorkeeper_routes.rb +17 -30
  377. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_discoverer.rb +38 -70
  378. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_table.rb +42 -74
  379. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/routes_parser.rb +280 -497
  380. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes.rb +54 -89
  381. data/plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline.rb +32 -54
  382. data/plugins/rigor-rbs-inline/lib/rigor-rbs-inline.rb +8 -13
  383. data/plugins/rigor-rspec/lib/rigor/plugin/rspec/analyzer.rb +9 -16
  384. data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_scope_index.rb +24 -39
  385. data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_type_resolver.rb +13 -22
  386. data/plugins/rigor-rspec/lib/rigor/plugin/rspec/matcher_analyzer.rb +34 -56
  387. data/plugins/rigor-rspec/lib/rigor/plugin/rspec/scope_walker.rb +22 -42
  388. data/plugins/rigor-rspec/lib/rigor/plugin/rspec.rb +43 -75
  389. data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails/have_http_status_analyzer.rb +27 -39
  390. data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails/http_status_codes.rb +14 -19
  391. data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails.rb +20 -34
  392. data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers/analyzer.rb +28 -47
  393. data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers.rb +21 -37
  394. data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/analyzer.rb +13 -22
  395. data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_discoverer.rb +18 -31
  396. data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_index.rb +6 -10
  397. data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq.rb +14 -29
  398. data/plugins/rigor-sinatra/lib/rigor/plugin/sinatra.rb +23 -41
  399. data/plugins/rigor-sinatra/lib/rigor-sinatra.rb +3 -5
  400. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/absurd_recognizer.rb +23 -38
  401. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/assertion_recognizer.rb +57 -96
  402. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog.rb +22 -35
  403. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog_walker.rb +41 -69
  404. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/method_signature.rb +6 -10
  405. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sig_parser.rb +24 -41
  406. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sigil_detector.rb +29 -50
  407. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/type_translator.rb +55 -88
  408. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet.rb +159 -262
  409. data/plugins/rigor-statesman/lib/rigor/plugin/statesman.rb +21 -29
  410. data/plugins/rigor-statesman/lib/rigor-statesman.rb +3 -5
  411. data/plugins/rigor-typescript-utility-types/lib/rigor/plugin/typescript_utility_types.rb +23 -37
  412. data/plugins/rigor-typescript-utility-types/lib/rigor-typescript-utility-types.rb +4 -6
  413. data/sig/rigor/scope.rbs +6 -0
  414. metadata +2 -1
@@ -4,53 +4,40 @@ require_relative "check_rules"
4
4
 
5
5
  module Rigor
6
6
  module Analysis
7
- # Single-source-of-truth metadata table for every CheckRule
8
- # the analyzer ships. Consumed by `rigor explain <rule>` so
9
- # users can read the same information the docs site eventually
10
- # publishes without leaving the terminal.
7
+ # Single-source-of-truth metadata table for every CheckRule the analyzer ships. Consumed by `rigor
8
+ # explain <rule>` so users can read the same information the docs site eventually publishes without
9
+ # leaving the terminal.
11
10
  #
12
11
  # Each entry carries:
13
12
  #
14
13
  # - `id` — canonical rule id (`call.undefined-method`).
15
14
  # - `summary` — single-line headline (≤ 80 chars).
16
- # - `fires_when` — bullet-shaped list of conditions that
17
- # trigger the rule, in the order a reader can scan
18
- # top-to-bottom.
19
- # - `does_not_fire_when` — explicit list of cases the rule
20
- # intentionally skips. Useful for "why am I NOT seeing
21
- # this diagnostic?" questions.
22
- # - `suppression`short note on how to suppress (in-source
23
- # `# rigor:disable` and the v0.1.2 file-scope variant
24
- # `# rigor:disable-file`, plus `.rigor.yml` `disable:`,
25
- # apply to every rule, so the note covers any rule-specific
26
- # nuance — e.g. unreachable-branch lives on the dead-branch
27
- # line, not the predicate line).
15
+ # - `fires_when` — bullet-shaped list of conditions that trigger the rule, in the order a reader can
16
+ # scan top-to-bottom.
17
+ # - `does_not_fire_when` — explicit list of cases the rule intentionally skips. Useful for "why am I NOT
18
+ # seeing this diagnostic?" questions.
19
+ # - `suppression` short note on how to suppress (in-source `# rigor:disable` and the v0.1.2
20
+ # file-scope variant `# rigor:disable-file`, plus `.rigor.yml` `disable:`, apply to every rule, so
21
+ # the note covers any rule-specific nuancee.g. unreachable-branch lives on the dead-branch line,
22
+ # not the predicate line).
28
23
  # - `severity_authored` — Symbol the rule emits with.
29
- # - `severity_by_profile` — Hash of `:lenient` / `:balanced`
30
- # / `:strict` to the configured severity per profile, taken
31
- # from `Configuration::SeverityProfile::PROFILES`.
32
- # - `evidence_tier` `:high` / `:medium` / `:low` (or `nil`
33
- # for informational helpers), Rigor's own confidence that a
34
- # firing is a true positive, derived from the rule's firing
35
- # gates. `:high` rules fire only on a concrete, statically-
36
- # known type with no metaprogramming escape (Rigor's false-
37
- # positive discipline has already filtered the uncertain
38
- # cases); `:medium` rules rest on flow / inference proofs
39
- # that inherit a documented FP envelope (loop / mutation /
40
- # RBS-strictness modelling gaps); `:low` rules are
41
- # resolution- or coverage-gap signals where a firing often
42
- # reflects missing context rather than a definite bug. The
43
- # tier routes a consumer's attention (and lets a downstream
44
- # classifier promote a `:high` firing without cross-tool
45
- # corroboration); it never feeds severity — that stays the
46
- # `severity_profile:` decision.
24
+ # - `severity_by_profile` — Hash of `:lenient` / `:balanced` / `:strict` to the configured severity per
25
+ # profile, taken from `Configuration::SeverityProfile::PROFILES`.
26
+ # - `evidence_tier` — `:high` / `:medium` / `:low` (or `nil` for informational helpers), Rigor's own
27
+ # confidence that a firing is a true positive, derived from the rule's firing gates. `:high` rules
28
+ # fire only on a concrete, statically- known type with no metaprogramming escape (Rigor's
29
+ # false-positive discipline has already filtered the uncertain cases); `:medium` rules rest on flow /
30
+ # inference proofs that inherit a documented FP envelope (loop / mutation / RBS-strictness modelling
31
+ # gaps); `:low` rules are resolution- or coverage-gap signals where a firing often reflects missing
32
+ # context rather than a definite bug. The tier routes a consumer's attention (and lets a downstream
33
+ # classifier promote a `:high` firing without cross-tool corroboration); it never feeds severity —
34
+ # that stays the `severity_profile:` decision.
47
35
  # - `since` — first version the rule shipped in.
48
36
  module RuleCatalog # rubocop:disable Metrics/ModuleLength
49
- # Stable documentation home for a built-in rule. `documentation_url`
50
- # appends a per-rule fragment that resolves to the rule's anchor in
51
- # the published diagnostics catalogue; the page itself points at
52
- # `rigor explain <rule>` as the authoritative per-rule reference.
53
- # Mirrors the gemspec `documentation_uri` URL scheme (`…/tree/main`).
37
+ # Stable documentation home for a built-in rule. `documentation_url` appends a per-rule fragment that
38
+ # resolves to the rule's anchor in the published diagnostics catalogue; the page itself points at
39
+ # `rigor explain <rule>` as the authoritative per-rule reference. Mirrors the gemspec
40
+ # `documentation_uri` URL scheme (`…/tree/main`).
54
41
  DOCUMENTATION_BASE = "https://github.com/rigortype/rigor/blob/main/docs/manual/04-diagnostics.md"
55
42
 
56
43
  class Entry < Data.define(:id, :summary, :fires_when, :does_not_fire_when,
@@ -65,10 +52,9 @@ module Rigor
65
52
  RuleCatalog.documentation_url(id)
66
53
  end
67
54
 
68
- # Hash-shaped form for `--format=json` consumers. Keys are
69
- # Strings so the payload is JSON-stable without a transform
70
- # pass. `evidence_tier` is omitted when nil (informational
71
- # helpers carry no confidence tier).
55
+ # Hash-shaped form for `--format=json` consumers. Keys are Strings so the payload is JSON-stable
56
+ # without a transform pass. `evidence_tier` is omitted when nil (informational helpers carry no
57
+ # confidence tier).
72
58
  def to_h
73
59
  base = {
74
60
  "id" => id,
@@ -131,11 +117,9 @@ module Rigor
131
117
  "`severity_overrides: { call.self-undefined-method: warning }` in `.rigor.yml`.",
132
118
  severity_authored: :warning,
133
119
  severity_by_profile: { lenient: :off, balanced: :off, strict: :off },
134
- # Off by default and metaprogramming-prone — a firing on a
135
- # class whose real surface the per-class scan cannot enumerate
136
- # (C-extension, `class << self`, dynamic accessors) is the
137
- # known FP mode, so a firing is a candidate to review, not a
138
- # high-confidence bug.
120
+ # Off by default and metaprogramming-prone — a firing on a class whose real surface the
121
+ # per-class scan cannot enumerate (C-extension, `class << self`, dynamic accessors) is the known
122
+ # FP mode, so a firing is a candidate to review, not a high-confidence bug.
139
123
  evidence_tier: :low,
140
124
  since: "0.1.17"
141
125
  ),
@@ -160,10 +144,9 @@ module Rigor
160
144
  "file in `.rigor.yml`'s `pre_eval:` so the analyzer sees the top-level `def` / patch.",
161
145
  severity_authored: :warning,
162
146
  severity_by_profile: { lenient: :off, balanced: :warning, strict: :error },
163
- # A firing is frequently a resolution gap — the defining file
164
- # is not in the analyzed set or injects the method via a
165
- # metaprogramming patch the analyzer does not see rather than
166
- # a definite typo, so it routes to the `pre_eval:` review path.
147
+ # A firing is frequently a resolution gap — the defining file is not in the analyzed set or
148
+ # injects the method via a metaprogramming patch the analyzer does not see rather than a
149
+ # definite typo, so it routes to the `pre_eval:` review path.
167
150
  evidence_tier: :low,
168
151
  since: "0.1.14"
169
152
  ),
@@ -303,8 +286,8 @@ module Rigor
303
286
  "points at the dead branch, not the predicate, so the suppression goes there).",
304
287
  severity_authored: :warning,
305
288
  severity_by_profile: { lenient: :info, balanced: :warning, strict: :error },
306
- # The literal-only firing envelope makes the deadness provable
307
- # from syntax alone — no inference uncertainty.
289
+ # The literal-only firing envelope makes the deadness provable from syntax alone — no inference
290
+ # uncertainty.
308
291
  evidence_tier: :high,
309
292
  since: "0.1.2"
310
293
  ),
@@ -328,10 +311,9 @@ module Rigor
328
311
  suppression: "`# rigor:disable always-truthy-condition` on the predicate line.",
329
312
  severity_authored: :warning,
330
313
  severity_by_profile: { lenient: :info, balanced: :warning, strict: :error },
331
- # Rests on inferred-constant folding, which inherits the
332
- # loop / mutation FP envelope the `does_not_fire_when` guards
333
- # narrow true positive in the common case, but not literal-
334
- # provable like `unreachable-branch`.
314
+ # Rests on inferred-constant folding, which inherits the loop / mutation FP envelope the
315
+ # `does_not_fire_when` guards narrow true positive in the common case, but not
316
+ # literal-provable like `unreachable-branch`.
335
317
  evidence_tier: :medium,
336
318
  since: "0.1.2"
337
319
  ),
@@ -355,11 +337,11 @@ module Rigor
355
337
  ],
356
338
  suppression: "`# rigor:disable unreachable-clause` on the dead-clause body line.",
357
339
  severity_authored: :warning,
358
- # ADR-47 WD4: balanced stays :info (one notch below its `flow.*`
359
- # siblings' :warning) until the regression-corpus FP gate is green.
340
+ # ADR-47 WD4: balanced stays :info (one notch below its `flow.*` siblings' :warning) until the
341
+ # regression-corpus FP gate is green.
360
342
  severity_by_profile: { lenient: :info, balanced: :info, strict: :warning },
361
- # Narrowing-driven proof that inherits the `always-truthy`
362
- # FP envelope; balanced keeps it `:info` pending the corpus gate.
343
+ # Narrowing-driven proof that inherits the `always-truthy` FP envelope; balanced keeps it `:info`
344
+ # pending the corpus gate.
363
345
  evidence_tier: :medium,
364
346
  since: "0.1.17"
365
347
  ),
@@ -382,10 +364,8 @@ module Rigor
382
364
  suppression: "`# rigor:disable dead-assignment` on the offending line, or rename the local to `_<name>`.",
383
365
  severity_authored: :warning,
384
366
  severity_by_profile: { lenient: :info, balanced: :warning, strict: :error },
385
- # The unread-write proof is reliable, but it flags a code
386
- # smell rather than a runtime fault, and the syntactic write
387
- # classification has narrow corners (the `does_not_fire_when`
388
- # exclusions).
367
+ # The unread-write proof is reliable, but it flags a code smell rather than a runtime fault, and
368
+ # the syntactic write classification has narrow corners (the `does_not_fire_when` exclusions).
389
369
  evidence_tier: :medium,
390
370
  since: "0.1.2"
391
371
  ),
@@ -408,9 +388,8 @@ module Rigor
408
388
  suppression: "`# rigor:disable def.return-type-mismatch`.",
409
389
  severity_authored: :warning,
410
390
  severity_by_profile: { lenient: :warning, balanced: :warning, strict: :error },
411
- # Depends on re-typing the body against an authored RBS return;
412
- # RBS strict-on-returns plus incomplete body inference makes a
413
- # firing usually-right but not concrete-call certain.
391
+ # Depends on re-typing the body against an authored RBS return; RBS strict-on-returns plus
392
+ # incomplete body inference makes a firing usually-right but not concrete-call certain.
414
393
  evidence_tier: :medium,
415
394
  since: "0.1.0"
416
395
  ),
@@ -456,9 +435,8 @@ module Rigor
456
435
  suppression: "`# rigor:disable def.override-visibility-reduced` on the override.",
457
436
  severity_authored: :warning,
458
437
  severity_by_profile: { lenient: :off, balanced: :warning, strict: :error },
459
- # Both the override and the shadowed ancestor visibility are
460
- # statically observed from project source — the substitutability
461
- # violation is concrete.
438
+ # Both the override and the shadowed ancestor visibility are statically observed from project
439
+ # source — the substitutability violation is concrete.
462
440
  evidence_tier: :high,
463
441
  since: "0.1.15"
464
442
  ),
@@ -487,8 +465,8 @@ module Rigor
487
465
  suppression: "`# rigor:disable def.override-return-widened` on the override.",
488
466
  severity_authored: :warning,
489
467
  severity_by_profile: { lenient: :off, balanced: :warning, strict: :error },
490
- # Gated on both-sides-authored RBS and a resolvable subtype
491
- # relationship, so a firing is a concrete covariance violation.
468
+ # Gated on both-sides-authored RBS and a resolvable subtype relationship, so a firing is a
469
+ # concrete covariance violation.
492
470
  evidence_tier: :high,
493
471
  since: "0.1.15"
494
472
  ),
@@ -520,8 +498,8 @@ module Rigor
520
498
  suppression: "`# rigor:disable def.override-param-narrowed` on the override.",
521
499
  severity_authored: :warning,
522
500
  severity_by_profile: { lenient: :off, balanced: :warning, strict: :error },
523
- # Gated on both-sides-authored RBS and a resolvable subtype
524
- # relationship, so a firing is a concrete contravariance violation.
501
+ # Gated on both-sides-authored RBS and a resolvable subtype relationship, so a firing is a
502
+ # concrete contravariance violation.
525
503
  evidence_tier: :high,
526
504
  since: "0.1.15"
527
505
  ),
@@ -544,8 +522,8 @@ module Rigor
544
522
  suppression: "`# rigor:disable ivar-write-mismatch` on the offending write.",
545
523
  severity_authored: :error,
546
524
  severity_by_profile: { lenient: :warning, balanced: :warning, strict: :error },
547
- # Both writes resolve to concrete classes before firing; the
548
- # union / Dynamic / clear-idiom escapes are excluded.
525
+ # Both writes resolve to concrete classes before firing; the union / Dynamic / clear-idiom
526
+ # escapes are excluded.
549
527
  evidence_tier: :high,
550
528
  since: "0.1.2"
551
529
  )
@@ -553,8 +531,7 @@ module Rigor
553
531
 
554
532
  module_function
555
533
 
556
- # Looks up a rule by canonical id, legacy alias, or family
557
- # wildcard. Returns an Array<Entry>:
534
+ # Looks up a rule by canonical id, legacy alias, or family wildcard. Returns an Array<Entry>:
558
535
  #
559
536
  # - canonical id → 1-element array,
560
537
  # - legacy alias → 1-element array (resolved to canonical),
@@ -580,12 +557,10 @@ module Rigor
580
557
  ENTRIES.values.sort_by(&:id)
581
558
  end
582
559
 
583
- # Rigor's confidence tier (`:high` / `:medium` / `:low`) that a
584
- # firing of `token` is a true positive, or nil for an
585
- # informational rule (`dump.type`) or an unknown / non-built-in
586
- # token (plugin and `rbs_extended.*` rules carry no built-in
587
- # tier). Resolves legacy aliases. See {Entry}'s `evidence_tier`
588
- # documentation for the tier semantics.
560
+ # Rigor's confidence tier (`:high` / `:medium` / `:low`) that a firing of `token` is a true positive,
561
+ # or nil for an informational rule (`dump.type`) or an unknown / non-built-in token (plugin and
562
+ # `rbs_extended.*` rules carry no built-in tier). Resolves legacy aliases. See {Entry}'s
563
+ # `evidence_tier` documentation for the tier semantics.
589
564
  def evidence_tier(token)
590
565
  entries = resolve(token)
591
566
  return nil unless entries.size == 1
@@ -593,12 +568,10 @@ module Rigor
593
568
  entries.first.evidence_tier
594
569
  end
595
570
 
596
- # Stable documentation URL for `token`, or nil for an unknown /
597
- # non-built-in token. The URL is the published diagnostics
598
- # catalogue page anchored at the rule's per-rule anchor
599
- # (`#rule-<id-with-dots-as-dashes>`); the page itself names
600
- # `rigor explain <rule>` as the authoritative per-rule reference.
601
- # Resolves legacy aliases to the canonical id.
571
+ # Stable documentation URL for `token`, or nil for an unknown / non-built-in token. The URL is the
572
+ # published diagnostics catalogue page anchored at the rule's per-rule anchor
573
+ # (`#rule-<id-with-dots-as-dashes>`); the page itself names `rigor explain <rule>` as the
574
+ # authoritative per-rule reference. Resolves legacy aliases to the canonical id.
602
575
  def documentation_url(token)
603
576
  entries = resolve(token)
604
577
  return nil unless entries.size == 1
@@ -606,9 +579,8 @@ module Rigor
606
579
  "#{DOCUMENTATION_BASE}##{doc_anchor(entries.first.id)}"
607
580
  end
608
581
 
609
- # The per-rule fragment a `documentation_url` points at:
610
- # `call.undefined-method` → `rule-call-undefined-method`. The
611
- # `04-diagnostics.md` catalogue carries the matching `<a id>`
582
+ # The per-rule fragment a `documentation_url` points at: `call.undefined-method` →
583
+ # `rule-call-undefined-method`. The `04-diagnostics.md` catalogue carries the matching `<a id>`
612
584
  # anchors.
613
585
  def doc_anchor(rule_id)
614
586
  "rule-#{rule_id.tr('.', '-')}"
@@ -4,35 +4,25 @@ require "rbconfig"
4
4
 
5
5
  module Rigor
6
6
  module Analysis
7
- # End-of-run telemetry for the `rigor check` CLI's `--stats`
8
- # output. Captures four cheap-to-measure groups:
7
+ # End-of-run telemetry for the `rigor check` CLI's `--stats` output. Captures four cheap-to-measure groups:
9
8
  #
10
- # - **Check targets** — the Ruby files the analyser actually
11
- # walks for diagnostics (`expand_paths` output).
12
- # - **Type universe** RBS class/module declarations the
13
- # analyser had visibility of, broken down by source:
14
- # `project_sig` (declarations whose source file lives under
15
- # the configured `signature_paths`) vs `bundled` (RBS core,
16
- # stdlib libraries, gem-bundled RBS everything outside
17
- # the project's own `sig/` tree).
18
- # - **Gem source-walk** — the ADR-10
19
- # `dependencies.source_inference` catalogue. Reports the
20
- # class count and the number of opt-in gems contributing.
9
+ # - **Check targets** — the Ruby files the analyser actually walks for diagnostics (`expand_paths` output).
10
+ # - **Type universe** — RBS class/module declarations the analyser had visibility of, broken down by
11
+ # source: `project_sig` (declarations whose source file lives under the configured `signature_paths`)
12
+ # vs `bundled` (RBS core, stdlib libraries, gem-bundled RBS — everything outside the project's own
13
+ # `sig/` tree).
14
+ # - **Gem source-walk** — the ADR-10 `dependencies.source_inference` catalogue. Reports the class count
15
+ # and the number of opt-in gems contributing.
21
16
  # - **Process** — wall-clock seconds + peak resident set size.
22
17
  #
23
- # The split between "check targets" and "type universe" makes
24
- # explicit that the analyser's diagnostic surface is bounded
25
- # by the user-controlled `paths:` configuration; the (typically
26
- # much larger) RBS class universe is symbol-discovery, not a
27
- # diagnostic surface.
18
+ # The split between "check targets" and "type universe" makes explicit that the analyser's diagnostic
19
+ # surface is bounded by the user-controlled `paths:` configuration; the (typically much larger) RBS
20
+ # class universe is symbol-discovery, not a diagnostic surface.
28
21
  #
29
- # Stats collection is intentionally cheap: wall + RSS are
30
- # single syscalls, target file count is already in
31
- # `expand_paths`, gem source-walk uses
32
- # `Index#class_to_gem.size`, and the RBS class breakdown
33
- # walks `class_decl_paths` (a frozen `Hash<String, String>`
34
- # populated once per environment by the RBS loader; ~1000-2000
35
- # entries × one `String#start_with?`).
22
+ # Stats collection is intentionally cheap: wall + RSS are single syscalls, target file count is already
23
+ # in `expand_paths`, gem source-walk uses `Index#class_to_gem.size`, and the RBS class breakdown walks
24
+ # `class_decl_paths` (a frozen `Hash<String, String>` populated once per environment by the RBS loader;
25
+ # ~1000-2000 entries × one `String#start_with?`).
36
26
  class RunStats
37
27
  attr_reader :wall_seconds, :peak_rss_bytes,
38
28
  :target_files,
@@ -56,13 +46,10 @@ module Rigor
56
46
  freeze
57
47
  end
58
48
 
59
- # Reports the process's resident set size in bytes. Source
60
- # ordering: `/proc/self/status` (Linux reads `VmHWM:`,
61
- # the peak RSS the kernel records) first; otherwise
62
- # `ps -o rss= -p <pid>` (macOS / BSD reports CURRENT
63
- # RSS, the closest universally-available proxy). Returns
64
- # nil when neither route works so the formatter can render
65
- # `unavailable` instead of misleading zero.
49
+ # Reports the process's resident set size in bytes. Source ordering: `/proc/self/status` (Linux — reads
50
+ # `VmHWM:`, the peak RSS the kernel records) first; otherwise `ps -o rss= -p <pid>` (macOS / BSD
51
+ # reports CURRENT RSS, the closest universally-available proxy). Returns nil when neither route works
52
+ # so the formatter can render `unavailable` instead of misleading zero.
66
53
  def self.peak_rss_bytes
67
54
  from_proc = read_vmhwm_from_proc
68
55
  return from_proc unless from_proc.nil?
@@ -96,22 +83,17 @@ module Rigor
96
83
  nil
97
84
  end
98
85
 
99
- # Source-attribution sentinel produced by `RBS::Environment`
100
- # entries restored from a cached blob (Marshal-loaded
101
- # `RBS::Environment` loses real file-path attribution; every
102
- # buffer reports `"<cached>"`). When every entry carries
103
- # this sentinel the partition_classes routine returns
104
- # `[0, total]` AND `attribution_available: false`, which
105
- # the format routine consumes to suppress the misleading
106
- # breakdown row.
86
+ # Source-attribution sentinel produced by `RBS::Environment` entries restored from a cached blob
87
+ # (Marshal-loaded `RBS::Environment` loses real file-path attribution; every buffer reports
88
+ # `"<cached>"`). When every entry carries this sentinel the partition_classes routine returns `[0,
89
+ # total]` AND `attribution_available: false`, which the format routine consumes to suppress the
90
+ # misleading breakdown row.
107
91
  CACHED_SENTINEL = "<cached>"
108
92
 
109
- # Computes `(project_sig, bundled)` counts from a frozen
110
- # `Hash<class_name => source_path>` snapshot and the
111
- # configured `signature_paths`. `project_sig` is the count
112
- # of classes whose source path begins with any of the
113
- # signature path prefixes (after expansion to absolute
114
- # paths); `bundled` is the remainder.
93
+ # Computes `(project_sig, bundled)` counts from a frozen `Hash<class_name => source_path>` snapshot and
94
+ # the configured `signature_paths`. `project_sig` is the count of classes whose source path begins
95
+ # with any of the signature path prefixes (after expansion to absolute paths); `bundled` is the
96
+ # remainder.
115
97
  def self.partition_classes(class_decl_paths:, signature_paths:)
116
98
  prefixes = Array(signature_paths).map { |p| File.expand_path(p.to_s) }
117
99
  return [0, class_decl_paths.size] if prefixes.empty?
@@ -124,33 +106,28 @@ module Rigor
124
106
  [project, class_decl_paths.size - project]
125
107
  end
126
108
 
127
- # True when at least one entry in `class_decl_paths` carries
128
- # a real source file path (i.e. not the cached-sentinel
129
- # marker). Used by callers to decide whether the
130
- # `project_sig` / `bundled` split is meaningful.
109
+ # True when at least one entry in `class_decl_paths` carries a real source file path (i.e. not the
110
+ # cached-sentinel marker). Used by callers to decide whether the `project_sig` / `bundled` split is
111
+ # meaningful.
131
112
  def self.attribution_available?(class_decl_paths:)
132
113
  return false if class_decl_paths.empty?
133
114
 
134
115
  class_decl_paths.each_value.any? { |path| path != CACHED_SENTINEL }
135
116
  end
136
117
 
137
- # Writes a human-facing rendering of the stats to `out`
138
- # (typically `$stderr` from the CLI). Format is intentionally
139
- # plain text JSON consumers should parse the structured
140
- # output of `rigor check --format=json` and consult `stats`
141
- # there.
118
+ # Writes a human-facing rendering of the stats to `out` (typically `$stderr` from the CLI). Format is
119
+ # intentionally plain text — JSON consumers should parse the structured output of `rigor check
120
+ # --format=json` and consult `stats` there.
142
121
  def format(out, prefix: "")
143
122
  out.puts("#{prefix}Check targets")
144
123
  out.puts("#{prefix} Ruby source files: #{@target_files}")
145
124
  out.puts("#{prefix}Type universe (symbol discovery; not analyzed for diagnostics)")
146
125
  out.puts("#{prefix} RBS classes available: #{@rbs_classes_total}")
147
126
  if @rbs_classes_total.zero?
148
- # A normal run always loads the bundled core+stdlib RBS (~1300+
149
- # classes), so zero means the environment failed to build (most
150
- # often a duplicate declaration in `signature_paths:`) and fell
151
- # back to empty type coverage is then near-useless but the run
152
- # still "succeeds". Surface it loudly so a broken setup is not
153
- # read as a clean analysis (the 20260620 field trial: redmine
127
+ # A normal run always loads the bundled core+stdlib RBS (~1300+ classes), so zero means the
128
+ # environment failed to build (most often a duplicate declaration in `signature_paths:`) and fell
129
+ # back to empty type coverage is then near-useless but the run still "succeeds". Surface it
130
+ # loudly so a broken setup is not read as a clean analysis (the 20260620 field trial: redmine
154
131
  # would otherwise wire a 0-coverage check into CI).
155
132
  out.puts("#{prefix} WARNING: the RBS environment is empty — it failed to build or loaded no")
156
133
  out.puts("#{prefix} signatures, so type coverage is severely limited (most diagnostics")