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
@@ -11,27 +11,21 @@ require_relative "../../rbs_extended/conformance_checker"
11
11
  module Rigor
12
12
  module Analysis
13
13
  class Runner
14
- # Owns the per-file analysis dispatch: the sequential coordinator
15
- # path (default) and both worker-pool backends the ADR-15
16
- # Phase 4b Ractor pool and the ADR-15 Amendment fork pool, plus the
17
- # pool-degraded fallback. Builds the coordinator-side Environment,
18
- # snapshots the end-of-pass RBS tables into the shared
19
- # {RunSnapshots}, and merges per-worker reporter drains back into
20
- # the runner's reporter accumulators.
14
+ # Owns the per-file analysis dispatch: the sequential coordinator path (default) and both worker-pool
15
+ # backends the ADR-15 Phase 4b Ractor pool and the ADR-15 Amendment fork pool, plus the
16
+ # pool-degraded fallback. Builds the coordinator-side Environment, snapshots the end-of-pass RBS
17
+ # tables into the shared {RunSnapshots}, and merges per-worker reporter drains back into the runner's
18
+ # reporter accumulators.
21
19
  #
22
- # Sequential-equivalence contract (docs/internal-spec/
23
- # worker-session.md): the pool path MUST produce the same
24
- # diagnostics, in the same order, as the sequential path. The
25
- # coordinator re-orders worker results by original path order and
26
- # replays per-worker reporter entries through the dedupe-on-record
20
+ # Sequential-equivalence contract (docs/internal-spec/ worker-session.md): the pool path MUST produce
21
+ # the same diagnostics, in the same order, as the sequential path. The coordinator re-orders worker
22
+ # results by original path order and replays per-worker reporter entries through the dedupe-on-record
27
23
  # APIs so reporter state matches a single-session run.
28
24
  #
29
- # Per-run varying prepass state (plugin registry, dependency-source
30
- # index, synthetic-method / project-patched indexes) is read
31
- # through injected reader procs; the actual per-file analysis is
32
- # delegated back through an injected `analyze_file` callable so the
33
- # CheckRules / recorder / plugin-emission machinery stays on the
34
- # {Runner}.
25
+ # Per-run varying prepass state (plugin registry, dependency-source index, synthetic-method /
26
+ # project-patched indexes) is read through injected reader procs; the actual per-file analysis is
27
+ # delegated back through an injected `analyze_file` callable so the CheckRules / recorder /
28
+ # plugin-emission machinery stays on the {Runner}.
35
29
  class PoolCoordinator # rubocop:disable Metrics/ClassLength
36
30
  # @param configuration [Rigor::Configuration]
37
31
  # @param cache_store [Rigor::Cache::Store, nil]
@@ -41,17 +35,15 @@ module Rigor
41
35
  # @param buffer [BufferBinding, nil]
42
36
  # @param environment_override [Rigor::Environment, nil]
43
37
  # @param rbs_extended_reporter [RbsExtended::Reporter]
44
- # @param boundary_cross_reporter
45
- # [DependencySourceInference::BoundaryCrossReporter]
46
- # @param source_rbs_synthesis_reporter
47
- # [Plugin::SourceRbsSynthesisReporter]
38
+ # @param boundary_cross_reporter [DependencySourceInference::BoundaryCrossReporter]
39
+ # @param source_rbs_synthesis_reporter [Plugin::SourceRbsSynthesisReporter]
48
40
  # @param snapshots [RunSnapshots] shared end-of-pass snapshot sink.
49
41
  # @param plugin_registry [#call] reader for the current registry.
50
42
  # @param dependency_source_index [#call] reader.
51
43
  # @param synthetic_method_index [#call] reader.
52
44
  # @param project_patched_methods [#call] reader.
53
- # @param project_scope_seed [#call] reader for the cross-file
54
- # pre-pass seed tables (`Runner#project_scope_seed_tables`).
45
+ # @param project_scope_seed [#call] reader for the cross-file pre-pass seed tables
46
+ # (`Runner#project_scope_seed_tables`).
55
47
  # @param analyze_file [#call] `(path, environment) -> diagnostics`.
56
48
  def initialize(configuration:, cache_store:, explain:, workers:, collect_stats:, # rubocop:disable Metrics/ParameterLists
57
49
  buffer:, environment_override:, rbs_extended_reporter:,
@@ -78,38 +70,29 @@ module Rigor
78
70
  @analyze_file = analyze_file
79
71
  end
80
72
 
81
- # ADR-15 Phase 4b — pool mode is enabled when `@workers > 0`.
82
- # Editor mode (`buffer:` non-nil) silently overrides pool
83
- # mode to sequential: per design § "Ractor pool mode", the
84
- # pool's warm-up cost dominates one-file wall time, so the
85
- # pool gains nothing on a per-buffer invocation. The override
86
- # is part of the contract — not a degradation diagnostic —
87
- # because `--workers=N` is a project-scale knob and editor
88
- # mode is per-buffer; the conflict resolves toward the more
89
- # specific axis.
73
+ # ADR-15 Phase 4b — pool mode is enabled when `@workers > 0`. Editor mode (`buffer:` non-nil)
74
+ # silently overrides pool mode to sequential: per design § "Ractor pool mode", the pool's warm-up
75
+ # cost dominates one-file wall time, so the pool gains nothing on a per-buffer invocation. The
76
+ # override is part of the contract not a degradation diagnostic — because `--workers=N` is a
77
+ # project-scale knob and editor mode is per-buffer; the conflict resolves toward the more specific
78
+ # axis.
90
79
  def pool_mode?
91
80
  return false unless @workers.is_a?(Integer) && @workers.positive?
92
81
 
93
82
  @buffer.nil?
94
83
  end
95
84
 
96
- # ADR-15 Phase 4b — routes per-file analysis to either the
97
- # sequential coordinator-side Environment (legacy path,
98
- # default) or a Ractor worker pool built around
99
- # {WorkerSession} (opt-in via `workers:`). The sequential
100
- # path is bit-for-bit unchanged from v0.1.4 / earlier; the
101
- # pool path is the substrate exercised by phase 4c when
102
- # `RIGOR_RACTOR_WORKERS` / `.rigor.yml` `parallel.workers:`
103
- # is wired.
85
+ # ADR-15 Phase 4b — routes per-file analysis to either the sequential coordinator-side Environment
86
+ # (legacy path, default) or a Ractor worker pool built around {WorkerSession} (opt-in via
87
+ # `workers:`). The sequential path is bit-for-bit unchanged from v0.1.4 / earlier; the pool path is
88
+ # the substrate exercised by phase 4c when `RIGOR_RACTOR_WORKERS` / `.rigor.yml`
89
+ # `parallel.workers:` is wired.
104
90
  #
105
- # Sequential mode also snapshots `class_decl_paths` from the
106
- # local environment after the per-file loop completes so
107
- # `RunStats` can attribute the RBS class universe between
108
- # project-sig and bundled sources. The env stays a LOCAL
109
- # variable (not an ivar) so it goes GC-eligible when the
110
- # method returns — holding it as long-lived state added
111
- # memory pressure that surfaced as a Bus Error during the
112
- # spec suite under Ruby 4.0 + rbs 4.0.2.
91
+ # Sequential mode also snapshots `class_decl_paths` from the local environment after the per-file
92
+ # loop completes so `RunStats` can attribute the RBS class universe between project-sig and bundled
93
+ # sources. The env stays a LOCAL variable (not an ivar) so it goes GC-eligible when the method
94
+ # returns — holding it as long-lived state added memory pressure that surfaced as a Bus Error
95
+ # during the spec suite under Ruby 4.0 + rbs 4.0.2.
113
96
  def analyze_files(files, environment: nil)
114
97
  return [] if files.empty?
115
98
  return dispatch_pool(files) if pool_mode?
@@ -118,19 +101,15 @@ module Rigor
118
101
  end
119
102
 
120
103
  def analyze_files_sequentially(files, environment)
121
- # Snapshot the small synthesized-namespace name list (NOT the
122
- # env see the method comment) so #run can surface the
123
- # malformed-RBS `:info` diagnostic without rebuilding the env.
124
- # Gated on the project actually declaring `signature_paths:`:
125
- # synthesis only matters for the project's own RBS, and
126
- # `#synthesized_namespaces` forces the (otherwise-lazy) RBS env
127
- # to build — doing so when there is no project sig set would
128
- # warm `.rigor/cache` on a bare `--no-stats` run.
104
+ # Snapshot the small synthesized-namespace name list (NOT the env — see the method comment) so
105
+ # #run can surface the malformed-RBS `:info` diagnostic without rebuilding the env. Gated on the
106
+ # project actually declaring `signature_paths:`: synthesis only matters for the project's own
107
+ # RBS, and `#synthesized_namespaces` forces the (otherwise-lazy) RBS env to build — doing so when
108
+ # there is no project sig set would warm `.rigor/cache` on a bare `--no-stats` run.
129
109
  @snapshots.synthesized_namespaces =
130
110
  project_signature_paths? ? (environment.rbs_loader&.synthesized_namespaces || []) : []
131
- # `rigor:v1:conforms-to` lives only in the project's own
132
- # `signature_paths:` RBS, so gate the scan the same way and
133
- # reuse the already-built env (no extra RBS load).
111
+ # `rigor:v1:conforms-to` lives only in the project's own `signature_paths:` RBS, so gate the scan
112
+ # the same way and reuse the already-built env (no extra RBS load).
134
113
  @snapshots.conformance_results =
135
114
  project_signature_paths? ? RbsExtended::ConformanceChecker.scan(environment.rbs_loader) : []
136
115
  result = files.flat_map { |path| @analyze_file.call(path, environment) }
@@ -142,12 +121,10 @@ module Rigor
142
121
  result
143
122
  end
144
123
 
145
- # Sequential-mode environment resolver. Returns the supplied
146
- # `environment:` override (with the runner's fresh per-run
147
- # reporter pair attached so dispatcher events route to THIS
148
- # runner's diagnostics) when present; otherwise builds a
149
- # fresh Environment per-call via {#build_runner_environment}
150
- # — preserving the pre-override behaviour bit-for-bit.
124
+ # Sequential-mode environment resolver. Returns the supplied `environment:` override (with the
125
+ # runner's fresh per-run reporter pair attached so dispatcher events route to THIS runner's
126
+ # diagnostics) when present; otherwise builds a fresh Environment per-call via
127
+ # {#build_runner_environment} preserving the pre-override behaviour bit-for-bit.
151
128
  def resolve_sequential_environment(source_files: [])
152
129
  return build_runner_environment(source_files: source_files) unless @environment_override
153
130
 
@@ -158,14 +135,11 @@ module Rigor
158
135
  @environment_override
159
136
  end
160
137
 
161
- # ADR-15 Amendment (2026-05-20) — worker-pool backend selector.
162
- # `fork` is the active backend: separate processes sidestep both
163
- # the Ruby Bug #22075 use-after-free and the worker-side
164
- # `Ractor::IsolationError` that make the Ractor pool unusable
165
- # (see the ADR-15 Amendment +
166
- # docs/notes/20260520-ractor-pool-cruby-uaf.md). The Ractor pool
167
- # is preserved but off the default path — `RIGOR_POOL_BACKEND=ractor`
168
- # opts back in so it stays testable. Platforms without `fork`
138
+ # ADR-15 Amendment (2026-05-20) — worker-pool backend selector. `fork` is the active backend:
139
+ # separate processes sidestep both the Ruby Bug #22075 use-after-free and the worker-side
140
+ # `Ractor::IsolationError` that make the Ractor pool unusable (see the ADR-15 Amendment +
141
+ # docs/notes/20260520-ractor-pool-cruby-uaf.md). The Ractor pool is preserved but off the default
142
+ # path `RIGOR_POOL_BACKEND=ractor` opts back in so it stays testable. Platforms without `fork`
169
143
  # (Windows) fall back to sequential.
170
144
  def pool_backend
171
145
  return :ractor if ENV["RIGOR_POOL_BACKEND"] == "ractor"
@@ -186,15 +160,12 @@ module Rigor
186
160
  end
187
161
  end
188
162
 
189
- # Coordinator-side Environment used by the sequential code
190
- # path. Pool mode builds one Environment per worker inside
191
- # the worker Ractor's body instead.
163
+ # Coordinator-side Environment used by the sequential code path. Pool mode builds one Environment
164
+ # per worker inside the worker Ractor's body instead.
192
165
  #
193
- # ADR-32 WD4 — `source_files:` is threaded down so that
194
- # `Environment.for_project` can invoke each loaded plugin's
195
- # `source_rbs_synthesizer` callable per project source file
196
- # at env-build time. Defaults to `[]` for callers that don't
197
- # have a file list yet (e.g. pre-pass-only build paths); in
166
+ # ADR-32 WD4 — `source_files:` is threaded down so that `Environment.for_project` can invoke each
167
+ # loaded plugin's `source_rbs_synthesizer` callable per project source file at env-build time.
168
+ # Defaults to `[]` for callers that don't have a file list yet (e.g. pre-pass-only build paths); in
198
169
  # that case no synthesised RBS is contributed.
199
170
  def build_runner_environment(source_files: [])
200
171
  Environment.for_project(
@@ -217,62 +188,44 @@ module Rigor
217
188
  )
218
189
  end
219
190
 
220
- # ADR-15 Phase 4b — Ractor pool around {WorkerSession}.
221
- # Spawns `@workers` Ractors; each takes the shareable
222
- # payload (Configuration, cache_root String, plugin
223
- # Blueprint Array, explain Boolean) and builds its OWN
224
- # WorkerSession internally. Files are distributed
225
- # round-robin across the pool; each worker writes back to
226
- # the main Ractor's mailbox via `Ractor.main.send` with
227
- # one of three message kinds:
191
+ # ADR-15 Phase 4b — Ractor pool around {WorkerSession}. Spawns `@workers` Ractors; each takes the
192
+ # shareable payload (Configuration, cache_root String, plugin Blueprint Array, explain Boolean) and
193
+ # builds its OWN WorkerSession internally. Files are distributed round-robin across the pool; each
194
+ # worker writes back to the main Ractor's mailbox via `Ractor.main.send` with one of three message
195
+ # kinds:
228
196
  #
229
- # - `[:prepare, diagnostics]` — once at startup, the
230
- # session's `prepare_diagnostics` snapshot. The
231
- # coordinator keeps the FIRST worker's snapshot only
232
- # (plugin `#prepare` is deterministic per plugin, so
233
- # each worker produces the same diagnostic set; surfacing
234
- # them once avoids N× duplication).
197
+ # - `[:prepare, diagnostics]` — once at startup, the session's `prepare_diagnostics` snapshot. The
198
+ # coordinator keeps the FIRST worker's snapshot only (plugin `#prepare` is deterministic per
199
+ # plugin, so each worker produces the same diagnostic set; surfacing them once avoids N×
200
+ # duplication).
235
201
  # - `[:file, path, diagnostics]` — one per analysed file.
236
- # - `[:done, drained_reporters]` — once at exit, the
237
- # per-worker reporter snapshots for end-of-pool merge.
202
+ # - `[:done, drained_reporters]` — once at exit, the per-worker reporter snapshots for end-of-pool
203
+ # merge.
238
204
  #
239
- # The Ruby 4.0+ Ractor model uses a single per-Ractor
240
- # mailbox (no `Ractor.yield`); workers push back via
241
- # `Ractor.main.send`. The coordinator drains its mailbox
242
- # via `Ractor.receive` until it has counted exactly
243
- # `pool.size` `:done` messages.
205
+ # The Ruby 4.0+ Ractor model uses a single per-Ractor mailbox (no `Ractor.yield`); workers push
206
+ # back via `Ractor.main.send`. The coordinator drains its mailbox via `Ractor.receive` until it has
207
+ # counted exactly `pool.size` `:done` messages.
244
208
  #
245
- # Diagnostic order: original path order. Workers may
246
- # complete files out of order; the coordinator re-orders
247
- # via the `results_by_path` Hash before flattening.
209
+ # Diagnostic order: original path order. Workers may complete files out of order; the coordinator
210
+ # re-orders via the `results_by_path` Hash before flattening.
248
211
  #
249
- # Reporter merge: per-worker `RbsExtended::Reporter` and
250
- # `BoundaryCrossReporter` entries are replayed into the
251
- # runner-side accumulators via their `record_*` APIs,
252
- # which dedupe on the same keys as a single-session run
253
- # would. Net result: reporter state is identical to the
254
- # sequential path.
212
+ # Reporter merge: per-worker `RbsExtended::Reporter` and `BoundaryCrossReporter` entries are
213
+ # replayed into the runner-side accumulators via their `record_*` APIs, which dedupe on the same
214
+ # keys as a single-session run would. Net result: reporter state is identical to the sequential
215
+ # path.
255
216
  def analyze_files_in_pool(files) # rubocop:disable Metrics/MethodLength,Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
256
- # Pre-warm class-level lazy memos on the MAIN Ractor.
257
- # `Environment::ClassRegistry.default` is the
258
- # default kwarg threaded through `Environment.new`
259
- # inside each worker session; lazy-initialising it
260
- # from a non-main Ractor would trip
261
- # `Ractor::IsolationError`. Touching it here forces
262
- # the (shareable) registry into the class-ivar cache
263
- # before any worker reads.
217
+ # Pre-warm class-level lazy memos on the MAIN Ractor. `Environment::ClassRegistry.default` is the
218
+ # default kwarg threaded through `Environment.new` inside each worker session; lazy-initialising
219
+ # it from a non-main Ractor would trip `Ractor::IsolationError`. Touching it here forces the
220
+ # (shareable) registry into the class-ivar cache before any worker reads.
264
221
  Environment::ClassRegistry.default
265
222
 
266
- # ADR-15 Phase 4b.x — pre-warm the RBS cache so
267
- # workers serve every reflection query from the
268
- # Marshal blob on disk. Without this, the first
269
- # cache MISS inside a worker falls through to
270
- # `RBS::EnvironmentLoader.new`, which reads a chain
271
- # of non-`Ractor.shareable?` RubyGems / RBS module
272
- # constants and raises `Ractor::IsolationError`.
273
- # Pre-warming requires a `cache_store`; the run aborts
274
- # to sequential mode otherwise. See ADR-15 Phase 4b.x
275
- # for the full chain of failing constants.
223
+ # ADR-15 Phase 4b.x — pre-warm the RBS cache so workers serve every reflection query from the
224
+ # Marshal blob on disk. Without this, the first cache MISS inside a worker falls through to
225
+ # `RBS::EnvironmentLoader.new`, which reads a chain of non-`Ractor.shareable?` RubyGems / RBS
226
+ # module constants and raises `Ractor::IsolationError`. Pre-warming requires a `cache_store`; the
227
+ # run aborts to sequential mode otherwise. See ADR-15 Phase 4b.x for the full chain of failing
228
+ # constants.
276
229
  if @cache_store.nil?
277
230
  return analyze_files_sequentially_fallback(
278
231
  files, reason: "pool mode requires a cache_store (--no-cache disables pool)"
@@ -284,11 +237,9 @@ module Rigor
284
237
  cache_root = @cache_store&.root
285
238
  blueprints = plugin_registry.blueprints
286
239
  explain = @explain
287
- # ADR-32 WD4 — the full project file list travels into
288
- # every Ractor worker so each worker's WorkerSession
289
- # can invoke loaded plugins' source_rbs_synthesizers at
290
- # env-build time. The list is a frozen Array<String>;
291
- # cheaply shareable.
240
+ # ADR-32 WD4 — the full project file list travels into every Ractor worker so each worker's
241
+ # WorkerSession can invoke loaded plugins' source_rbs_synthesizers at env-build time. The list is
242
+ # a frozen Array<String>; cheaply shareable.
292
243
  shareable_source_files = files.map { |path| path.to_s.dup.freeze }.freeze
293
244
 
294
245
  pool = Array.new(@workers) do
@@ -340,22 +291,18 @@ module Rigor
340
291
  Array(prepare_diagnostics) + files.flat_map { |path| results_by_path.fetch(path, []) }
341
292
  end
342
293
 
343
- # ADR-15 Amendment (2026-05-20) — fork-based worker pool, the
344
- # active backend for `workers > 0`. Builds ONE {WorkerSession}
345
- # on the parent, then `fork`s N children that copy-on-write
346
- # inherit it. Each child analyses a contiguous slice of `files`
347
- # and writes a Marshal'd `{results:, reporters:}` payload to a
348
- # temp file; the parent `Process.wait`s every child, merges the
349
- # payloads, and re-orders diagnostics by original path order.
294
+ # ADR-15 Amendment (2026-05-20) — fork-based worker pool, the active backend for `workers > 0`.
295
+ # Builds ONE {WorkerSession} on the parent, then `fork`s N children that copy-on-write inherit it.
296
+ # Each child analyses a contiguous slice of `files` and writes a Marshal'd `{results:, reporters:}`
297
+ # payload to a temp file; the parent `Process.wait`s every child, merges the payloads, and re-orders
298
+ # diagnostics by original path order.
350
299
  #
351
- # Separate processes have separate GC heaps and `vm->ci_table`
352
- # (immune to Ruby Bug #22075) and copy-on-write-inherit every
353
- # constant (no `Ractor.shareable?` constraint). See the ADR-15
354
- # Amendment + docs/notes/20260520-ractor-pool-cruby-uaf.md.
300
+ # Separate processes have separate GC heaps and `vm->ci_table` (immune to Ruby Bug #22075) and
301
+ # copy-on-write-inherit every constant (no `Ractor.shareable?` constraint). See the ADR-15 Amendment
302
+ # + docs/notes/20260520-ractor-pool-cruby-uaf.md.
355
303
  #
356
- # A child that exits non-zero (crash / unmarshalable payload) is
357
- # degraded: the parent re-analyses that slice in-process and
358
- # prepends a `pool-degraded` warning.
304
+ # A child that exits non-zero (crash / unmarshalable payload) is degraded: the parent re-analyses
305
+ # that slice in-process and prepends a `pool-degraded` warning.
359
306
  def analyze_files_in_fork_pool(files) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
360
307
  Environment::ClassRegistry.default
361
308
 
@@ -369,9 +316,8 @@ module Rigor
369
316
  project_scope_seed: project_scope_seed,
370
317
  source_files: files
371
318
  )
372
- # Force the full RBS load on the parent so children
373
- # copy-on-write inherit a warm Environment rather than each
374
- # rebuilding it after the fork.
319
+ # Force the full RBS load on the parent so children copy-on-write inherit a warm Environment
320
+ # rather than each rebuilding it after the fork.
375
321
  session.environment.rbs_loader&.prewarm
376
322
  snapshot_fork_pool_stats(session) if @collect_stats
377
323
 
@@ -398,10 +344,9 @@ module Rigor
398
344
  degraded.empty? ? diagnostics : diagnostics.unshift(fork_degraded_diagnostic(degraded.size))
399
345
  end
400
346
 
401
- # Child-process body for {#analyze_files_in_fork_pool}. Analyses
402
- # the slice with the copy-on-write-inherited session and writes
403
- # the Marshal'd payload to `out_path`. `exit!` skips `at_exit` /
404
- # stdio flush — the payload is already durable on disk by then.
347
+ # Child-process body for {#analyze_files_in_fork_pool}. Analyses the slice with the
348
+ # copy-on-write-inherited session and writes the Marshal'd payload to `out_path`. `exit!` skips
349
+ # `at_exit` / stdio flush — the payload is already durable on disk by then.
405
350
  def run_fork_worker(session, slice, out_path)
406
351
  results = slice.to_h { |path| [path, session.analyze(path)] }
407
352
  payload = { results: results, reporters: session.drain_reporters }
@@ -411,17 +356,16 @@ module Rigor
411
356
  exit!(1)
412
357
  end
413
358
 
414
- # Snapshots `class_decl_paths` from the parent session's loader
415
- # so end-of-run {RunStats} can attribute the RBS class universe.
359
+ # Snapshots `class_decl_paths` from the parent session's loader so end-of-run {RunStats} can
360
+ # attribute the RBS class universe.
416
361
  def snapshot_fork_pool_stats(session)
417
362
  loader = session.environment.rbs_loader
418
363
  @snapshots.class_decl_paths = loader&.class_decl_paths || {}.freeze
419
364
  @snapshots.signature_paths = loader&.signature_paths || [].freeze
420
365
  end
421
366
 
422
- # Waits for every forked child, merges each successful payload
423
- # into `results_by_path`, and returns the file paths whose
424
- # worker exited abnormally (for in-process degrade).
367
+ # Waits for every forked child, merges each successful payload into `results_by_path`, and returns
368
+ # the file paths whose worker exited abnormally (for in-process degrade).
425
369
  def collect_fork_results(children, results_by_path)
426
370
  degraded = []
427
371
  children.each do |child|
@@ -437,10 +381,9 @@ module Rigor
437
381
  degraded
438
382
  end
439
383
 
440
- # @return [Hash, nil] the child's `{results:, reporters:}`
441
- # payload, or nil when the child exited abnormally or wrote no
442
- # readable payload. `Marshal.load` is safe here: the blob was
443
- # written by our own forked child to a temp file we created.
384
+ # @return [Hash, nil] the child's `{results:, reporters:}` payload, or nil when the child exited
385
+ # abnormally or wrote no readable payload. `Marshal.load` is safe here: the blob was written by
386
+ # our own forked child to a temp file we created.
444
387
  def fork_worker_payload(status, out_path)
445
388
  return nil unless status.success? && File.exist?(out_path)
446
389
 
@@ -458,15 +401,11 @@ module Rigor
458
401
  )
459
402
  end
460
403
 
461
- # ADR-15 Phase 4b.x — drives every cached RBS producer
462
- # on the main Ractor so each worker can serve all
463
- # reflection queries from disk (Marshal-load only).
464
- # Builds a single coordinator-side {Environment} for
465
- # this purpose; the env object is discarded immediately
466
- # after the cache is warm — workers build their own
467
- # `Environment.for_project` inside the Ractor body,
468
- # which then routes through `cached_env` instead of
469
- # `RBS::EnvironmentLoader.new`.
404
+ # ADR-15 Phase 4b.x — drives every cached RBS producer on the main Ractor so each worker can serve
405
+ # all reflection queries from disk (Marshal-load only). Builds a single coordinator-side
406
+ # {Environment} for this purpose; the env object is discarded immediately after the cache is warm
407
+ # workers build their own `Environment.for_project` inside the Ractor body, which then routes
408
+ # through `cached_env` instead of `RBS::EnvironmentLoader.new`.
470
409
  def prewarm_rbs_cache_for_pool
471
410
  warm_env = Environment.for_project(
472
411
  libraries: @configuration.libraries,
@@ -481,14 +420,10 @@ module Rigor
481
420
  warm_env.rbs_loader&.prewarm
482
421
  end
483
422
 
484
- # ADR-15 Phase 4b.x — pool-mode safety net. When pool
485
- # mode is configured but a precondition fails (currently:
486
- # `--no-cache` would force workers through
487
- # `EnvironmentLoader.new`), degrade to sequential
488
- # analysis with a `:warning` `pool-degraded` diagnostic
489
- # at run start. The actual per-file analysis runs on
490
- # the coordinator, identical to the default sequential
491
- # path.
423
+ # ADR-15 Phase 4b.x — pool-mode safety net. When pool mode is configured but a precondition fails
424
+ # (currently: `--no-cache` would force workers through `EnvironmentLoader.new`), degrade to
425
+ # sequential analysis with a `:warning` `pool-degraded` diagnostic at run start. The actual
426
+ # per-file analysis runs on the coordinator, identical to the default sequential path.
492
427
  def analyze_files_sequentially_fallback(files, reason:)
493
428
  environment = build_runner_environment
494
429
  diagnostics = files.flat_map { |path| @analyze_file.call(path, environment) }
@@ -524,10 +459,8 @@ module Rigor
524
459
  rbs_display: entry.rbs_display
525
460
  )
526
461
  end
527
- # ADR-32 WD6 — merge per-worker synthesizer failures
528
- # back into the coordinator's reporter. Fetched with a
529
- # default empty array so older drains (pre-slice-2)
530
- # remain compatible.
462
+ # ADR-32 WD6 — merge per-worker synthesizer failures back into the coordinator's reporter. Fetched
463
+ # with a default empty array so older drains (pre-slice-2) remain compatible.
531
464
  Array(drained[:source_rbs_synthesis]).each do |entry|
532
465
  @source_rbs_synthesis_reporter.record(
533
466
  plugin_id: entry.plugin_id, path: entry.path, message: entry.message
@@ -537,8 +470,8 @@ module Rigor
537
470
 
538
471
  private
539
472
 
540
- # True when the project declares its own `signature_paths:` (the
541
- # only place the qualified-name-without-namespace mistake lives).
473
+ # True when the project declares its own `signature_paths:` (the only place the
474
+ # qualified-name-without-namespace mistake lives).
542
475
  def project_signature_paths?
543
476
  paths = @configuration.signature_paths
544
477
  !(paths.nil? || paths.empty?)