rigortype 0.3.9 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (363) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  3. data/data/core_overlay/enumerable.rbs +51 -0
  4. data/data/core_overlay/enumerator.rbs +84 -0
  5. data/data/core_overlay/hash_rbs3.rbs +41 -0
  6. data/data/core_overlay/process.rbs +40 -0
  7. data/data/core_overlay/string_io.rbs +33 -0
  8. data/data/effects/core.yml +3 -3
  9. data/data/gem_overlay/activesupport/core_ext.rbs +127 -4
  10. data/docs/handbook/03-narrowing.md +95 -10
  11. data/docs/handbook/04-tuples-and-shapes.md +8 -6
  12. data/docs/handbook/07-rbs-and-extended.md +16 -11
  13. data/docs/handbook/10-sorbet.md +9 -10
  14. data/docs/handbook/11-sig-gen.md +454 -13
  15. data/docs/manual/02-cli-reference.md +63 -2
  16. data/docs/manual/03-configuration.md +7 -0
  17. data/docs/manual/04-diagnostics.md +4 -0
  18. data/docs/manual/07-plugins.md +1 -1
  19. data/docs/manual/10-mcp-server.md +3 -2
  20. data/docs/manual/16-rbs-extended-annotations.md +40 -7
  21. data/docs/manual/19-effect-labels.md +10 -0
  22. data/docs/manual/plugins/README.md +7 -0
  23. data/docs/manual/plugins/rigor-actioncable.md +8 -1
  24. data/docs/manual/plugins/rigor-actionmailer.md +7 -0
  25. data/docs/manual/plugins/rigor-actionpack.md +243 -0
  26. data/docs/manual/plugins/rigor-active-model-serializers.md +153 -0
  27. data/docs/manual/plugins/rigor-activejob.md +7 -0
  28. data/docs/manual/plugins/rigor-activerecord.md +110 -4
  29. data/docs/manual/plugins/rigor-activestorage.md +8 -1
  30. data/docs/manual/plugins/rigor-activesupport-core-ext.md +11 -5
  31. data/docs/manual/plugins/rigor-grape.md +106 -0
  32. data/docs/manual/plugins/rigor-graphql.md +23 -2
  33. data/docs/manual/plugins/rigor-pundit.md +8 -1
  34. data/docs/manual/plugins/rigor-rails-i18n.md +10 -5
  35. data/docs/manual/plugins/rigor-rails-routes.md +7 -0
  36. data/docs/manual/plugins/rigor-rbs-inline.md +212 -25
  37. data/docs/manual/plugins/rigor-sidekiq.md +8 -1
  38. data/docs/manual/plugins/rigor-sorbet.md +21 -5
  39. data/exe/rigor +19 -4
  40. data/lib/rigor/analysis/baseline.rb +1 -1
  41. data/lib/rigor/analysis/check_rules/declaration_sourced_guard.rb +167 -2
  42. data/lib/rigor/analysis/check_rules/lexical_method_sites.rb +189 -0
  43. data/lib/rigor/analysis/check_rules/main_pass_collector.rb +5 -3
  44. data/lib/rigor/analysis/check_rules/rule_ids.rb +20 -5
  45. data/lib/rigor/analysis/check_rules/rule_walk.rb +2 -1
  46. data/lib/rigor/analysis/check_rules/source_arity.rb +323 -0
  47. data/lib/rigor/analysis/check_rules/special_global_setters.rb +146 -0
  48. data/lib/rigor/analysis/check_rules/unreachable_clause_collector.rb +36 -2
  49. data/lib/rigor/analysis/check_rules.rb +520 -49
  50. data/lib/rigor/analysis/dependency_recorder.rb +23 -0
  51. data/lib/rigor/analysis/fact_store.rb +9 -0
  52. data/lib/rigor/analysis/incremental.rb +26 -0
  53. data/lib/rigor/analysis/incremental_session.rb +36 -4
  54. data/lib/rigor/analysis/project_scan.rb +11 -1
  55. data/lib/rigor/analysis/reachability/plugin_roots.rb +0 -1
  56. data/lib/rigor/analysis/reachability/scan_cache.rb +1 -0
  57. data/lib/rigor/analysis/rule_catalog.rb +127 -0
  58. data/lib/rigor/analysis/run_cache_key.rb +20 -11
  59. data/lib/rigor/analysis/runner/diagnostic_aggregator.rb +167 -11
  60. data/lib/rigor/analysis/runner/effect_envelope_pass.rb +9 -4
  61. data/lib/rigor/analysis/runner/pool_coordinator.rb +107 -15
  62. data/lib/rigor/analysis/runner/project_pre_passes.rb +26 -7
  63. data/lib/rigor/analysis/runner.rb +278 -20
  64. data/lib/rigor/analysis/template_unit_collector.rb +303 -0
  65. data/lib/rigor/analysis/template_unit_paths.rb +91 -0
  66. data/lib/rigor/analysis/template_unit_positions.rb +293 -0
  67. data/lib/rigor/analysis/template_units.rb +399 -0
  68. data/lib/rigor/analysis/worker_session.rb +53 -10
  69. data/lib/rigor/bleeding_edge.rb +0 -2
  70. data/lib/rigor/builtins/hkt_builtins.rb +1 -0
  71. data/lib/rigor/builtins/imported_refinements.rb +4 -0
  72. data/lib/rigor/builtins/regex_refinement.rb +17 -9
  73. data/lib/rigor/builtins/static_return_refinements.rb +2 -0
  74. data/lib/rigor/cache/descriptor.rb +6 -1
  75. data/lib/rigor/cache/engine_source.rb +29 -1
  76. data/lib/rigor/cache/incremental_snapshot.rb +33 -1
  77. data/lib/rigor/cache/rbs_cache_producer.rb +4 -0
  78. data/lib/rigor/cache/rbs_descriptor.rb +37 -7
  79. data/lib/rigor/cache/store.rb +0 -1
  80. data/lib/rigor/ci_detector.rb +1 -0
  81. data/lib/rigor/cli/doc_links.rb +1 -1
  82. data/lib/rigor/cli/docs_command.rb +4 -4
  83. data/lib/rigor/cli/plugin_command.rb +3 -3
  84. data/lib/rigor/cli/prism_colorizer.rb +0 -1
  85. data/lib/rigor/cli/sig_gen_command.rb +210 -29
  86. data/lib/rigor/cli/skill_command.rb +1 -1
  87. data/lib/rigor/cli/skill_describe.rb +0 -1
  88. data/lib/rigor/cli/type_of_command.rb +19 -5
  89. data/lib/rigor/cli/type_of_renderer.rb +20 -9
  90. data/lib/rigor/cli/type_of_template_probe.rb +189 -0
  91. data/lib/rigor/cli.rb +21 -3
  92. data/lib/rigor/configuration/severity_profile.rb +19 -3
  93. data/lib/rigor/configuration.rb +66 -3
  94. data/lib/rigor/effects/ancestry_recorder.rb +191 -0
  95. data/lib/rigor/effects/attribution.rb +11 -2
  96. data/lib/rigor/effects/callee_rule.rb +368 -0
  97. data/lib/rigor/effects/catalog.rb +7 -4
  98. data/lib/rigor/effects/collector.rb +11 -5
  99. data/lib/rigor/effects/config_envelopes.rb +9 -2
  100. data/lib/rigor/effects/definition_context.rb +179 -0
  101. data/lib/rigor/effects/effect_table.rb +11 -3
  102. data/lib/rigor/effects/envelope_check.rb +1 -1
  103. data/lib/rigor/effects/envelope_index.rb +15 -0
  104. data/lib/rigor/effects/file_collection.rb +59 -5
  105. data/lib/rigor/effects/framework_units.rb +1 -1
  106. data/lib/rigor/effects/identity.rb +16 -0
  107. data/lib/rigor/effects/local_ownership.rb +38 -12
  108. data/lib/rigor/effects/method_key.rb +21 -0
  109. data/lib/rigor/effects/mutation_classifier.rb +23 -12
  110. data/lib/rigor/effects/plugin_facts.rb +43 -31
  111. data/lib/rigor/effects/propagator.rb +295 -16
  112. data/lib/rigor/effects/registry.rb +1 -1
  113. data/lib/rigor/effects/scanner.rb +121 -72
  114. data/lib/rigor/effects/signature_sources.rb +1 -1
  115. data/lib/rigor/effects/snapshot.rb +2 -1
  116. data/lib/rigor/effects/summary.rb +27 -4
  117. data/lib/rigor/effects/unit_scan.rb +385 -30
  118. data/lib/rigor/effects/visibility.rb +101 -0
  119. data/lib/rigor/environment/lockfile_resolver.rb +17 -0
  120. data/lib/rigor/environment/member_consistency/comparator.rb +708 -0
  121. data/lib/rigor/environment/member_consistency.rb +298 -0
  122. data/lib/rigor/environment/rbs_loader.rb +399 -133
  123. data/lib/rigor/environment.rb +103 -38
  124. data/lib/rigor/hashing/xxh3.rb +264 -0
  125. data/lib/rigor/inference/acceptance.rb +139 -9
  126. data/lib/rigor/inference/block_auto_splat.rb +216 -0
  127. data/lib/rigor/inference/block_call_timing.rb +338 -0
  128. data/lib/rigor/inference/block_parameter_binder.rb +73 -27
  129. data/lib/rigor/inference/block_repetition.rb +71 -0
  130. data/lib/rigor/inference/body_fixpoint.rb +2 -1
  131. data/lib/rigor/inference/budget_trace.rb +2 -1
  132. data/lib/rigor/inference/builtins/method_catalog.rb +2 -1
  133. data/lib/rigor/inference/builtins/string_catalog.rb +1 -1
  134. data/lib/rigor/inference/captured_locals.rb +387 -15
  135. data/lib/rigor/inference/closure_escape_analyzer.rb +157 -13
  136. data/lib/rigor/inference/content_join.rb +200 -27
  137. data/lib/rigor/inference/def_return_typer.rb +11 -7
  138. data/lib/rigor/inference/define_method_block_self.rb +64 -0
  139. data/lib/rigor/inference/element_read_widening.rb +22 -10
  140. data/lib/rigor/inference/error_info.rb +196 -0
  141. data/lib/rigor/inference/expression_typer.rb +1532 -496
  142. data/lib/rigor/inference/external_ancestor_resolution.rb +267 -0
  143. data/lib/rigor/inference/fresh_frame_blocks.rb +127 -0
  144. data/lib/rigor/inference/global_write_census.rb +239 -0
  145. data/lib/rigor/inference/guard_rebinding.rb +447 -0
  146. data/lib/rigor/inference/hash_lookup_mutation.rb +88 -0
  147. data/lib/rigor/inference/index_write_widening.rb +16 -3
  148. data/lib/rigor/inference/indexed_narrowing.rb +61 -9
  149. data/lib/rigor/inference/jump_targets.rb +82 -0
  150. data/lib/rigor/inference/last_line/implicit_self.rb +210 -0
  151. data/lib/rigor/inference/last_line/self_evidence.rb +329 -0
  152. data/lib/rigor/inference/last_line.rb +340 -0
  153. data/lib/rigor/inference/last_status.rb +144 -0
  154. data/lib/rigor/inference/macro_block_self_type.rb +167 -17
  155. data/lib/rigor/inference/match_rebinding/calls.rb +281 -0
  156. data/lib/rigor/inference/match_rebinding/frame.rb +148 -0
  157. data/lib/rigor/inference/match_rebinding/operands.rb +236 -0
  158. data/lib/rigor/inference/match_rebinding/self_calls.rb +83 -0
  159. data/lib/rigor/inference/match_rebinding.rb +392 -0
  160. data/lib/rigor/inference/method_dispatcher/alias_strict_nominals.rb +36 -0
  161. data/lib/rigor/inference/method_dispatcher/block_folding.rb +85 -24
  162. data/lib/rigor/inference/method_dispatcher/facet_distribution.rb +147 -0
  163. data/lib/rigor/inference/method_dispatcher/hash_transform_keys_folding.rb +191 -0
  164. data/lib/rigor/inference/method_dispatcher/iterator_dispatch.rb +4 -0
  165. data/lib/rigor/inference/method_dispatcher/match_data_folding.rb +159 -0
  166. data/lib/rigor/inference/method_dispatcher/overload_selector.rb +113 -73
  167. data/lib/rigor/inference/method_dispatcher/process_folding.rb +56 -0
  168. data/lib/rigor/inference/method_dispatcher/proven_overload.rb +72 -0
  169. data/lib/rigor/inference/method_dispatcher/rbs_dispatch.rb +881 -38
  170. data/lib/rigor/inference/method_dispatcher/self_substitute.rb +142 -0
  171. data/lib/rigor/inference/method_dispatcher/shape_dispatch.rb +128 -53
  172. data/lib/rigor/inference/method_dispatcher/struct_folding.rb +1 -1
  173. data/lib/rigor/inference/method_dispatcher.rb +214 -13
  174. data/lib/rigor/inference/method_parameter_binder.rb +8 -3
  175. data/lib/rigor/inference/multi_target_binder.rb +340 -52
  176. data/lib/rigor/inference/mutation_rejoin.rb +4 -1
  177. data/lib/rigor/inference/mutation_widening.rb +70 -48
  178. data/lib/rigor/inference/narrowing.rb +540 -120
  179. data/lib/rigor/inference/operand_effects.rb +167 -0
  180. data/lib/rigor/inference/operand_walk.rb +88 -0
  181. data/lib/rigor/inference/optimistic_origin.rb +152 -9
  182. data/lib/rigor/inference/parameter_inference_collector.rb +3 -2
  183. data/lib/rigor/inference/project_method_ownership.rb +136 -0
  184. data/lib/rigor/inference/project_patched_methods.rb +7 -2
  185. data/lib/rigor/inference/project_patched_scanner.rb +7 -3
  186. data/lib/rigor/inference/receiver_alias.rb +90 -1
  187. data/lib/rigor/inference/receiver_blind_block.rb +219 -0
  188. data/lib/rigor/inference/refinement_mutation.rb +15 -11
  189. data/lib/rigor/inference/repeated_or_writes.rb +463 -0
  190. data/lib/rigor/inference/return_barrier.rb +54 -0
  191. data/lib/rigor/inference/rewrite_mutation.rb +120 -0
  192. data/lib/rigor/inference/scope_indexer.rb +4615 -551
  193. data/lib/rigor/inference/statement_evaluator.rb +3176 -490
  194. data/lib/rigor/inference/stored_block_call.rb +54 -0
  195. data/lib/rigor/inference/string_mutation.rb +44 -7
  196. data/lib/rigor/inference/unknown_store_widening.rb +200 -0
  197. data/lib/rigor/inference/unthreaded_rebinds.rb +282 -0
  198. data/lib/rigor/language_server/debouncer.rb +0 -1
  199. data/lib/rigor/language_server/diagnostic_publisher.rb +3 -2
  200. data/lib/rigor/language_server/hover_renderer.rb +3 -3
  201. data/lib/rigor/language_server/project_context.rb +5 -3
  202. data/lib/rigor/mcp/server.rb +2 -1
  203. data/lib/rigor/plugin/base.rb +168 -5
  204. data/lib/rigor/plugin/box_probe.rb +91 -0
  205. data/lib/rigor/plugin/bundled_catalog.rb +1 -1
  206. data/lib/rigor/plugin/effect_attribution.rb +58 -4
  207. data/lib/rigor/plugin/loader.rb +2 -1
  208. data/lib/rigor/plugin/macro/block_as_method.rb +45 -6
  209. data/lib/rigor/plugin/manifest.rb +71 -10
  210. data/lib/rigor/plugin/registry.rb +35 -1
  211. data/lib/rigor/plugin/source_rbs_synthesis_reporter.rb +9 -3
  212. data/lib/rigor/plugin/template_unit.rb +196 -0
  213. data/lib/rigor/plugin.rb +1 -0
  214. data/lib/rigor/protection/discovery_seed.rb +3 -1
  215. data/lib/rigor/protection/kill_signature.rb +0 -1
  216. data/lib/rigor/protection/mutation_cache.rb +1 -2
  217. data/lib/rigor/rbs_extended.rb +27 -0
  218. data/lib/rigor/reflection/constant_ancestors.rb +97 -0
  219. data/lib/rigor/reflection/constant_path.rb +19 -6
  220. data/lib/rigor/reflection.rb +72 -105
  221. data/lib/rigor/scope/discovery_index.rb +135 -2
  222. data/lib/rigor/scope.rb +859 -49
  223. data/lib/rigor/sig_gen/alias_index.rb +289 -0
  224. data/lib/rigor/sig_gen/classification.rb +22 -5
  225. data/lib/rigor/sig_gen/declaration_equivalence.rb +127 -0
  226. data/lib/rigor/sig_gen/effect_annotation.rb +202 -0
  227. data/lib/rigor/sig_gen/generator.rb +558 -31
  228. data/lib/rigor/sig_gen/inline_declarations.rb +184 -0
  229. data/lib/rigor/sig_gen/method_candidate.rb +47 -3
  230. data/lib/rigor/sig_gen/observation_collector.rb +1 -1
  231. data/lib/rigor/sig_gen/renderer.rb +124 -9
  232. data/lib/rigor/sig_gen/skip_reason_catalog.rb +44 -1
  233. data/lib/rigor/sig_gen/write_result.rb +19 -3
  234. data/lib/rigor/sig_gen/writer.rb +166 -35
  235. data/lib/rigor/sig_gen.rb +3 -0
  236. data/lib/rigor/signature_path_audit.rb +1 -1
  237. data/lib/rigor/source/node_walker.rb +0 -3
  238. data/lib/rigor/source/parameter_envelope.rb +72 -0
  239. data/lib/rigor/source.rb +1 -0
  240. data/lib/rigor/type/combinator.rb +88 -12
  241. data/lib/rigor/type/difference.rb +1 -0
  242. data/lib/rigor/type/hash_shape.rb +1 -1
  243. data/lib/rigor/type/refined.rb +1 -0
  244. data/lib/rigor/version.rb +1 -1
  245. data/lib/rigor.rb +1 -0
  246. data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/effects.rb +1 -0
  247. data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable.rb +9 -5
  248. data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer.rb +13 -4
  249. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/analyzer.rb +0 -1
  250. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_scan.rb +96 -0
  251. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/effects.rb +65 -8
  252. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/erb_compiler.rb +270 -0
  253. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/render_locals.rb +402 -0
  254. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/view_assigns.rb +370 -0
  255. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/view_units.rb +132 -0
  256. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack.rb +239 -4
  257. data/plugins/rigor-actionpack/sig/action_view.rbs +43 -0
  258. data/plugins/rigor-active-model-serializers/lib/rigor/plugin/active_model_serializers/serializer_discoverer.rb +220 -0
  259. data/plugins/rigor-active-model-serializers/lib/rigor/plugin/active_model_serializers/serializer_index.rb +56 -0
  260. data/plugins/rigor-active-model-serializers/lib/rigor/plugin/active_model_serializers.rb +263 -0
  261. data/plugins/rigor-active-model-serializers/lib/rigor-active-model-serializers.rb +7 -0
  262. data/plugins/rigor-active-model-serializers/sig/active_model_serializers.rbs +45 -0
  263. data/plugins/rigor-activejob/lib/rigor/plugin/activejob/effects.rb +1 -0
  264. data/plugins/rigor-activejob/lib/rigor/plugin/activejob.rb +9 -5
  265. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/analyzer.rb +35 -3
  266. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/effects.rb +72 -12
  267. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_discoverer.rb +380 -3
  268. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_index.rb +14 -6
  269. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord.rb +281 -35
  270. data/plugins/rigor-activerecord/sig/active_record/relation.rbs +206 -31
  271. data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage.rb +25 -14
  272. data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext/effects.rb +9 -2
  273. data/plugins/rigor-activesupport-core-ext/sig/active_support/core_ext.rbs +171 -5
  274. data/plugins/rigor-dry-monads/lib/rigor/plugin/dry_monads.rb +2 -0
  275. data/plugins/rigor-ethon/lib/rigor/plugin/ethon.rb +1 -0
  276. data/plugins/rigor-ffi/lib/rigor/plugin/ffi/types.rb +1 -1
  277. data/plugins/rigor-grape/lib/rigor/plugin/grape.rb +141 -0
  278. data/plugins/rigor-grape/lib/rigor-grape.rb +6 -0
  279. data/plugins/rigor-grape/sig/grape.rbs +263 -0
  280. data/plugins/rigor-graphql/lib/rigor/plugin/graphql.rb +72 -2
  281. data/plugins/rigor-graphql/sig/graphql.rbs +485 -0
  282. data/plugins/rigor-minitest/lib/rigor/plugin/minitest/assertion_analyzer.rb +2 -0
  283. data/plugins/rigor-pundit/lib/rigor/plugin/pundit.rb +11 -7
  284. data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n.rb +35 -37
  285. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/analyzer.rb +0 -1
  286. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/devise_routes.rb +2 -0
  287. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/doorkeeper_routes.rb +1 -0
  288. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes.rb +9 -17
  289. data/plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline/same_line_annotations.rb +149 -0
  290. data/plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline.rb +217 -36
  291. data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/schedule_scan.rb +1 -0
  292. data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq.rb +9 -5
  293. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sigil_detector.rb +0 -1
  294. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet.rb +46 -1
  295. data/plugins/rigor-sorbet/sig/sorbet.rbs +277 -0
  296. data/sig/rigor/analysis/baseline.rbs +69 -7
  297. data/sig/rigor/analysis/fact_store.rbs +1 -1
  298. data/sig/rigor/analysis/project_scan.rbs +74 -0
  299. data/sig/rigor/effects/config_envelopes.rbs +100 -0
  300. data/sig/rigor/effects/effect_table.rbs +60 -0
  301. data/sig/rigor/effects/envelope.rbs +97 -0
  302. data/sig/rigor/effects/envelope_index.rbs +33 -0
  303. data/sig/rigor/effects/file_collection.rbs +81 -0
  304. data/sig/rigor/effects/label.rbs +26 -0
  305. data/sig/rigor/effects/label_set.rbs +46 -0
  306. data/sig/rigor/effects/method_key.rbs +24 -0
  307. data/sig/rigor/effects/origin.rbs +50 -0
  308. data/sig/rigor/effects/plugin_facts.rbs +141 -0
  309. data/sig/rigor/effects/registry.rbs +68 -0
  310. data/sig/rigor/effects/summary.rbs +50 -0
  311. data/sig/rigor/effects/taint_cause.rbs +12 -0
  312. data/sig/rigor/environment.rbs +12 -10
  313. data/sig/rigor/inference/optimistic_origin.rbs +10 -0
  314. data/sig/rigor/inference.rbs +6 -4
  315. data/sig/rigor/plugin/additional_initializer.rbs +36 -0
  316. data/sig/rigor/plugin/base.rbs +30 -7
  317. data/sig/rigor/plugin/effect_ancestry.rbs +27 -0
  318. data/sig/rigor/plugin/effect_attribution.rbs +66 -0
  319. data/sig/rigor/plugin/effect_edge.rbs +33 -0
  320. data/sig/rigor/plugin/effect_entry_points.rbs +25 -0
  321. data/sig/rigor/plugin/io_boundary.rbs +1 -1
  322. data/sig/rigor/plugin/loader.rbs +3 -3
  323. data/sig/rigor/plugin/manifest.rbs +50 -11
  324. data/sig/rigor/plugin/protocol_contract.rbs +68 -0
  325. data/sig/rigor/plugin/registry.rbs +62 -1
  326. data/sig/rigor/plugin.rbs +1 -1
  327. data/sig/rigor/rbs_extended.rbs +1 -1
  328. data/sig/rigor/reflection.rbs +7 -6
  329. data/sig/rigor/scope.rbs +135 -20
  330. data/sig/rigor/sig_gen/skip_reason_catalog.rbs +14 -7
  331. data/sig/rigor/source.rbs +4 -4
  332. data/sig/rigor/testing.rbs +10 -4
  333. data/sig/rigor/type.rbs +6 -0
  334. data/sig/rigor.rbs +38 -20
  335. data/skills/rigor-ask/SKILL.md +8 -5
  336. data/skills/rigor-baseline-reduce/SKILL.md +4 -6
  337. data/skills/rigor-ci-setup/SKILL.md +17 -21
  338. data/skills/rigor-doctor/SKILL.md +24 -22
  339. data/skills/rigor-doctor/references/01-checks.md +97 -33
  340. data/skills/rigor-editor-setup/SKILL.md +6 -4
  341. data/skills/rigor-mcp-setup/SKILL.md +5 -4
  342. data/skills/rigor-monkeypatch-resolve/SKILL.md +5 -3
  343. data/skills/rigor-next-steps/SKILL.md +4 -2
  344. data/skills/rigor-plugin-author/SKILL.md +19 -23
  345. data/skills/rigor-plugin-author/references/01-plan-and-scaffold.md +9 -8
  346. data/skills/rigor-plugin-author/references/02-walker-and-types.md +12 -25
  347. data/skills/rigor-plugin-author/references/03-test-and-ship.md +6 -8
  348. data/skills/rigor-plugin-review/SKILL.md +6 -4
  349. data/skills/rigor-plugin-review/references/01-best-practices-checklist.md +2 -1
  350. data/skills/rigor-plugin-tune/SKILL.md +4 -2
  351. data/skills/rigor-project-init/SKILL.md +9 -7
  352. data/skills/rigor-project-init/references/01-detect.md +13 -9
  353. data/skills/rigor-project-init/references/02-configure.md +33 -8
  354. data/skills/rigor-project-init/references/03-baseline-and-bugs.md +14 -14
  355. data/skills/rigor-project-init/references/04-sig-uplift.md +27 -14
  356. data/skills/rigor-protection-uplift/SKILL.md +4 -6
  357. data/skills/rigor-rbs-setup/SKILL.md +4 -2
  358. data/skills/rigor-type-oracle/SKILL.md +4 -6
  359. data/skills/rigor-type-oracle/references/01-oracle-commands.md +12 -8
  360. data/skills/rigor-type-oracle/references/03-gap-protocol.md +0 -3
  361. data/skills/rigor-unused-adjudicate/SKILL.md +4 -2
  362. data/skills/rigor-upgrade/SKILL.md +13 -8
  363. metadata +108 -1
@@ -29,6 +29,14 @@ module Rigor
29
29
  # The {TypeTranslator} table documents coverage. Most of Sorbet's vocabulary translates; remaining
30
30
  # gaps (`T.proc`, `T::Struct` subclasses, `T.attached_class`, etc.) degrade silently to `Dynamic[top]`.
31
31
  #
32
+ # Issue #1097 — the plugin also ships `sig/sorbet.rbs`, a bundled declaration of the annotation DSL
33
+ # surface itself: `T`'s type-expression functions, the `T::X[...]` constructors, `T::Sig`'s `sig`
34
+ # verb (reached via the manifest `rbs_complete_extends:` bridge over `extend T::Sig`), the
35
+ # `DeclBuilder` the sig block `instance_eval`s on (via `block_as_methods:`), and the
36
+ # `T::Struct` / `T::Enum` family (via `rbs_complete_ancestors:`). The value-side assertions
37
+ # (`T.let`/`T.cast`/`T.must`/…) stay recogniser-owned — RBS cannot express "return the asserted
38
+ # type" — and `T`'s declared surface is intentionally partial behind `open_receivers:`.
39
+ #
32
40
  # Architecture: per-run `Catalog` is built lazily on first access by walking every configured `paths:`
33
41
  # entry's `.rb` files plus every `rbi_paths:` entry's `.rbi` files (slice 4) via the plugin's
34
42
  # `IoBoundary`. The catalog is frozen after the first build and consulted by the `dynamic_return` rule
@@ -70,7 +78,43 @@ module Rigor
70
78
  # effect of recursing into the parent root.
71
79
  "rbi_paths" => { kind: :array, default: ["sorbet/rbi"] },
72
80
  "enforce_sigil" => { kind: :boolean, default: true }
73
- }
81
+ },
82
+ # #1097 — bundled sorbet-runtime DSL surface (`sig/sorbet.rbs`). `sig` itself reaches the
83
+ # class object through `extend T::Sig` (or the `< T::ImmutableStruct` / `< T::Enum`
84
+ # family, which carry the edge themselves), which is
85
+ # why `rbs_complete_extends:` — the extend-edge allow-list — carries `T::Sig` /
86
+ # `T::Helpers` / `T::Generic`, and `rbs_complete_ancestors:` carries the Struct/Enum family
87
+ # for the subclass bridge.
88
+ signature_paths: ["sig"],
89
+ rbs_complete_extends: %w[T::Sig T::Helpers T::Generic],
90
+ rbs_complete_ancestors: %w[T::Struct T::InexactStruct T::ImmutableStruct T::Enum],
91
+ # `sig { ... }` bodies are `instance_eval`'d on a `DeclBuilder`
92
+ # (`T::Private::Methods._run_builder`), so `params` / `returns` / `void` resolve on the
93
+ # builder, not the enclosing class. `T::Sig::WithoutRuntime.sig` is the direct-call twin —
94
+ # a singleton method on the module, matching by name equality.
95
+ block_as_methods: [
96
+ Rigor::Plugin::Macro::BlockAsMethod.new(
97
+ receiver_constraint: "T::Sig",
98
+ method_names: %i[sig],
99
+ self_type: "T::Private::Methods::DeclBuilder"
100
+ ),
101
+ Rigor::Plugin::Macro::BlockAsMethod.new(
102
+ receiver_constraint: "T::Sig::WithoutRuntime",
103
+ method_names: %i[sig],
104
+ self_type: "T::Private::Methods::DeclBuilder"
105
+ )
106
+ ],
107
+ # The declared surface is deliberately partial — `T` is an open module whose runtime
108
+ # surface is much larger than the DSL (version-dependent internals, `T::Private::*`,
109
+ # `T::Configuration`, `T::Utils`). Open receivers keep an unmodelled `T.something` opaque
110
+ # rather than a `call.undefined-method` false positive. `DeclBuilder` is NOT open —
111
+ # `sig { typo }` is a real bug and stays a diagnostic.
112
+ open_receivers: %w[T T::Sig T::Sig::WithoutRuntime T::Helpers T::Generic
113
+ T::Utils T::Configuration T::Private T::Private::Methods
114
+ T::Props T::Props::ClassMethods T::Props::CustomType
115
+ T::Types T::Types::Base T::Array T::Hash T::Set
116
+ T::Enumerable T::Enumerator T::Range T::Class
117
+ T::InexactStruct T::Struct T::ImmutableStruct T::Enum]
74
118
  )
75
119
 
76
120
  def init(services)
@@ -441,6 +485,7 @@ module Rigor
441
485
  # Frozen empty bundle used when the `:catalog` producer failed (e.g. a project I/O error) so downstream
442
486
  # reads see a well-formed shape rather than nil.
443
487
  EMPTY_CATALOG_BUNDLE = { catalog: Catalog.new.freeze!, sigil_by_path: {}, parse_errors_by_path: {} }.freeze
488
+ Ractor.make_shareable(EMPTY_CATALOG_BUNDLE)
444
489
  private_constant :EMPTY_CATALOG_BUNDLE
445
490
 
446
491
  # @param root — directory or single file.
@@ -0,0 +1,277 @@
1
+ # Bundled RBS for the sorbet-runtime annotation DSL (issue #1097).
2
+ #
3
+ # sorbet-runtime ships RBI, not RBS, so none of the annotation surface (`T`, `T::Sig`, the
4
+ # `DeclBuilder` behind `sig { ... }`, the `T::Array[...]` constructors, the `T::Helpers` /
5
+ # `T::Generic` class macros) resolves for the analyzer. This file declares that surface so the
6
+ # DSL *expressions themselves* type; the plugin's `AssertionRecognizer` continues to own the
7
+ # value-sensitive calls (`T.let` / `T.cast` / `T.must` / `T.bind` / `T.assert_type!` /
8
+ # `T.reveal_type` / `T.unsafe`) ahead of this RBS — the signatures here deliberately agree with
9
+ # it (`T.unsafe` stays `untyped`, `T.bind` returns `nil`) for the cases the recognizer declines.
10
+ #
11
+ # Provenance (docs/agents/type-authoring.md): `rigor sig-gen` cannot produce this file — the DSL
12
+ # methods are installed by `Module#extend` hooks and `instance_eval` in sorbet-runtime's source
13
+ # (sorbet-runtime 0.5.11766, `lib/types/{sig,_types,generic,helpers,struct,enum}.rb` and
14
+ # `lib/types/private/methods/decl_builder.rb`), so every entry was hand-derived by reading that
15
+ # source. Members that do not exist at that version's runtime location are deliberately absent.
16
+ #
17
+ # Two Rigor-side mechanisms complete the picture (manifest fields):
18
+ #
19
+ # - `rbs_complete_extends:` — `extend T::Sig` in a class/module body is what puts `sig` on the
20
+ # class object's singleton; the dispatch bridge resolves those calls through the module's
21
+ # instance surface declared here.
22
+ # - `block_as_methods:` — `sig`'s block is `instance_eval`'d on a `DeclBuilder`
23
+ # (`T::Private::Methods.declare_sig` → `DeclBuilder#instance_eval`), so `sig` bodies bind
24
+ # `self` to `T::Private::Methods::DeclBuilder`, NOT to the enclosing class.
25
+
26
+ module T
27
+ # `T::Boolean` is a runtime constant (`T.any(TrueClass, FalseClass)` → a `T::Types::Union`
28
+ # instance), not a module — it appears in `params`/`returns` argument position as a const read.
29
+ Boolean: ::T::Types::Union
30
+
31
+ # The type-ASSERTION functions (`T.let`, `T.cast`, `T.assert_type!`, `T.bind`, `T.must`,
32
+ # `T.must_because`, `T.reveal_type`, `T.absurd`, `T.unsafe`) are deliberately NOT declared here.
33
+ # Their static return is the *asserted* type (the second argument, translated) or the nil-stripped
34
+ # inner type — semantics RBS cannot express — so the plugin's `AssertionRecognizer` /
35
+ # `AbsurdRecognizer` owns them ahead of dispatch, and a declined call degrades through `T`'s
36
+ # `open_receivers:` entry to opaque rather than a wrong `X` reading.
37
+
38
+ # Type-expression constructors — used in `params`/`returns` argument position.
39
+ def self.nilable: (untyped type) -> ::T::Types::Base
40
+ def self.untyped: () -> ::T::Types::Base
41
+ def self.noreturn: () -> ::T::Types::Base
42
+ def self.anything: () -> ::T::Types::Base
43
+ def self.all: (untyped type_a, untyped type_b, *untyped types) -> ::T::Types::Base
44
+ def self.any: (untyped type_a, untyped type_b, *untyped types) -> ::T::Types::Base
45
+ def self.class_of: (untyped arg) -> ::T::Types::Base
46
+ def self.self_type: () -> ::T::Types::Base
47
+ def self.attached_class: () -> ::T::Types::Base
48
+ def self.type_parameter: (::Symbol name) -> ::T::Types::TypeParameter
49
+ # `type=nil, &blk` — the positional form is a kept-for-migration legacy path (`_types.rb`);
50
+ # the block form wraps in `T::Private::Types::TypeAlias`.
51
+ def self.type_alias: (?untyped type) ?{ () -> untyped } -> ::T::Types::Base
52
+
53
+ # `T.proc` returns a DeclBuilder in `Modes.proc` (`T::Private::Methods.start_proc`), so the
54
+ # `T.proc.params(x: Integer).returns(String)` chain resolves through the same builder surface.
55
+ def self.proc: () -> ::T::Private::Methods::DeclBuilder
56
+ end
57
+
58
+ # `T::Sig` is a mixin a class EXTENDS (`extend T::Sig`) to gain the class-level `sig` verb —
59
+ # sorbet-runtime does not patch `Module`. `sig` itself returns nil at runtime
60
+ # (`declare_sig` stores the DeclarationBlock and returns nil).
61
+ module T::Sig
62
+ def sig: (?untyped arg0) ?{ () -> untyped } -> nil
63
+
64
+ # `T::Sig::WithoutRuntime.sig { ... }` is a no-op shim for contexts where the runtime wrapper
65
+ # cannot be installed; it is called ON the module, so `sig` here is a module-singleton method.
66
+ # `extend T::Sig::WithoutRuntime` installs nothing at runtime, so no instance `sig` is declared.
67
+ module WithoutRuntime
68
+ def self.sig: (?untyped arg0) ?{ () -> untyped } -> nil
69
+ end
70
+ end
71
+
72
+ # The builder `sig`'s block is `instance_eval`'d on (`DeclBuilder#instance_eval(&blk)` via
73
+ # `T::Private::Methods._run_builder`). Every DSL method returns `self` so the
74
+ # `params(...).returns(...).checked(:always)` chain keeps typing.
75
+ class T::Private::Methods::DeclBuilder
76
+ def params: (*untyped unused_positional_params, **untyped params) -> self
77
+ def returns: (untyped type) -> self
78
+ def void: () -> self
79
+ def bind: (untyped type) -> self
80
+ def checked: (untyped level) -> self
81
+ def on_failure: (*untyped args) -> self
82
+ def abstract: () -> self
83
+ def final: () -> self
84
+ def override: (?allow_incompatible: bool | Symbol) -> self
85
+ def overridable: () -> self
86
+ def type_parameters: (*untyped names) -> self
87
+ end
88
+
89
+ # The `T::X[...]` type constructors are modules with a singleton `[]` (`_types.rb`), returning the
90
+ # corresponding `T::Types::TypedX` instance. The carriers below exist so the constructor's return
91
+ # reads as a real nominal rather than `Dynamic[top]`.
92
+ module T::Array
93
+ def self.[]: (untyped type) -> ::T::Types::TypedArray
94
+ end
95
+
96
+ module T::Hash
97
+ def self.[]: (untyped keys, untyped values) -> ::T::Types::TypedHash
98
+ end
99
+
100
+ module T::Set
101
+ def self.[]: (untyped type) -> ::T::Types::TypedSet
102
+ end
103
+
104
+ module T::Enumerable
105
+ def self.[]: (untyped type) -> ::T::Types::TypedEnumerable
106
+ end
107
+
108
+ module T::Enumerator
109
+ def self.[]: (untyped type) -> ::T::Types::TypedEnumerator
110
+ end
111
+
112
+ module T::Range
113
+ def self.[]: (untyped type) -> ::T::Types::TypedRange
114
+ end
115
+
116
+ module T::Class
117
+ def self.[]: (untyped type) -> ::T::Types::TypedClass
118
+ end
119
+
120
+ # Carrier classes for the `T::X[...]` constructors and the `T.*` type-expression functions. The
121
+ # internal `T::Types::*` class names are the runtime classes (`types/types/*.rb`).
122
+ module T::Types
123
+ class Base
124
+ end
125
+
126
+ class TypedArray < Base
127
+ end
128
+
129
+ class TypedHash < Base
130
+ end
131
+
132
+ class TypedSet < Base
133
+ end
134
+
135
+ class TypedEnumerable < Base
136
+ end
137
+
138
+ class TypedEnumerator < Base
139
+ end
140
+
141
+ class TypedRange < Base
142
+ end
143
+
144
+ class TypedClass < Base
145
+ end
146
+
147
+ class Union < Base
148
+ end
149
+
150
+ class Intersection < Base
151
+ end
152
+
153
+ class TypeParameter < Base
154
+ end
155
+
156
+ class TypeMember < Base
157
+ end
158
+
159
+ class TypeTemplate < Base
160
+ end
161
+
162
+ class Proc < Base
163
+ end
164
+ end
165
+
166
+ # `extend T::Helpers` installs the class/module declaration macros (`abstract!`, `interface!`,
167
+ # `final!`, `sealed!`, `requires_ancestor`, `mixes_in_class_methods`). All return void-ish values
168
+ # from `T::Private::{Abstract,Final,Sealed}` bookkeeping (`helpers.rb`).
169
+ module T::Helpers
170
+ def abstract!: () -> void
171
+ def interface!: () -> void
172
+ def final!: () -> void
173
+ def sealed!: () -> void
174
+ def mixes_in_class_methods: (::Module mod, *::Module mods) -> void
175
+ def requires_ancestor: () { () -> untyped } -> void
176
+ end
177
+
178
+ # `extend T::Generic` installs the type-member macros — `Elem = type_member` is the common shape
179
+ # (`generic.rb`). `[]` is the generic-application stub (`def [](*types); self; end`).
180
+ module T::Generic
181
+ # `generic.rb` — `extend T::Generic` alone also installs the helper macros: the module
182
+ # `include`s `T::Helpers` (and `Kernel`), so its instance surface carries `abstract!` et al.
183
+ include T::Helpers
184
+
185
+ def []: (*untyped types) -> self
186
+ def type_member: (?untyped variance) ?{ () -> untyped } -> ::T::Types::TypeMember
187
+ def type_template: (?untyped variance) ?{ () -> untyped } -> ::T::Types::TypeTemplate
188
+ def has_attached_class!: (?untyped variance) ?{ () -> untyped } -> void
189
+ end
190
+
191
+ # `T::Props` is the property mixin; its `included` hook `extend`s the includer with
192
+ # `ClassMethods` (`mixes_in_class_methods`), which is where `prop` / `const` live. The hook itself
193
+ # is not modelled — `include T::Props` alone does not put `prop` on the class in this
194
+ # declaration either — but the `T::Struct` family below declares the same `extend` edges directly,
195
+ # matching the runtime outcome for `< T::Struct` subclasses.
196
+ module T::Props
197
+ module ClassMethods
198
+ def prop: (::Symbol name, untyped cls, **untyped rules) -> void
199
+ def const: (::Symbol name, untyped cls_or_args, **untyped args) -> void
200
+ def props: () -> ::Hash[untyped, untyped]
201
+ def plugins: () -> ::Array[untyped]
202
+ def decorator: () -> ::T::Props::Decorator
203
+ def decorator_class: () -> ::Class
204
+ def validate_prop_value: (untyped prop, untyped val) -> void
205
+ def plugin: (untyped mod) -> void
206
+ end
207
+
208
+ class Decorator
209
+ end
210
+
211
+ module CustomType
212
+ end
213
+
214
+ module Serializable
215
+ # `serializable.rb` — lifted onto includers via `mixes_in_class_methods`.
216
+ module ClassMethods
217
+ def prop_by_serialized_forms: () -> ::Hash[untyped, untyped]
218
+ def from_hash: (untyped hash, ?bool strict) -> untyped
219
+ def from_hash!: (untyped hash) -> untyped
220
+ end
221
+ end
222
+
223
+ module Plugin
224
+ # `plugin.rb` — `mixes_in_class_methods(ClassMethods)`; `included` re-registers the plugin
225
+ # (`child.plugin(self)`), which is what extends `plugin::ClassMethods` onto the target.
226
+ module ClassMethods
227
+ def included: (untyped child) -> void
228
+ end
229
+ end
230
+ end
231
+
232
+ # The `T::Struct` family. `struct.rb` has `T::InexactStruct` `include T::Props` (+Serializable,
233
+ # +Constructor); the `mixes_in_class_methods` hooks extend `T::Props::ClassMethods` (then the
234
+ # registered `T::Props::Plugin::ClassMethods`) and `T::Props::Serializable::ClassMethods` onto the
235
+ # class — verified against the runtime singleton ancestry. Neither `T::Sig` nor `T::Helpers` is
236
+ # extended here: `sig` inside a `class Doc < T::Struct` body raises at runtime unless the subclass
237
+ # adds `extend T::Sig` itself (dependabot's `TokenBucket` does exactly that). Only
238
+ # `T::ImmutableStruct` extends `T::Sig` (`struct.rb` — it annotates its own `initialize`). The
239
+ # edges are declared directly so subclasses resolve `prop` / `const` / `from_hash` through the
240
+ # `rbs_complete_ancestors` superclass bridge.
241
+ class T::InexactStruct
242
+ extend T::Props::ClassMethods
243
+ extend T::Props::Plugin::ClassMethods
244
+ extend T::Props::Serializable::ClassMethods
245
+ end
246
+
247
+ class T::Struct < T::InexactStruct
248
+ end
249
+
250
+ class T::ImmutableStruct < T::InexactStruct
251
+ extend T::Sig
252
+ end
253
+
254
+ # `T::Enum` — `enum.rb` `extend`s `T::Sig` and `T::Props::CustomType`; `enums` `yield`s its block
255
+ # so `X = new` inside keeps the subclass's class-object self.
256
+ class T::Enum
257
+ extend T::Sig
258
+ extend T::Props::CustomType
259
+
260
+ def self.enums: () { () -> untyped } -> void
261
+ def serialize: () -> ::String
262
+ end
263
+
264
+ # Namespace-only declarations so bare const reads (`T::Utils`, `T::Configuration`,
265
+ # `T::Private::Methods`) type as `Singleton[...]` instead of `Dynamic[top]`. Their singleton
266
+ # surface is intentionally NOT modelled — they are covered by `open_receivers:` so calls on them
267
+ # degrade to opaque rather than firing `call.undefined-method` on an unmodelled private API.
268
+ module T::Utils
269
+ end
270
+
271
+ module T::Configuration
272
+ end
273
+
274
+ module T::Private
275
+ module Methods
276
+ end
277
+ end
@@ -6,26 +6,88 @@ module Rigor
6
6
  class LoadError < ::StandardError
7
7
  end
8
8
 
9
+ # Tuple-shaped bucket key so rule-ID rows and message-pattern rows coexist: `message_regex` is
10
+ # `nil` for rule-ID rows and a `Regexp` for message-pattern rows; `rule` and `file` are always
11
+ # present (parse_row raises without them; the generator's group key carries both). `count`
12
+ # intentionally shadows `Struct#count` — PHPStan-compatible field name.
13
+ class Bucket < ::Struct[untyped]
14
+ # sig-gen gap: #1183 — Struct member types are not inferred from construction sites; every
15
+ # member row in this class (and the keyword ctor below) is hand-written.
16
+ def file: () -> String
17
+ # sig-gen gap: #1183 — as above.
18
+ def rule: () -> String
19
+ # sig-gen gap: #1183 — as above.
20
+ def message_regex: () -> Regexp?
21
+ # sig-gen gap: #1183 — as above.
22
+ def count: () -> Integer
23
+ # sig-gen gap: #1183 — as above.
24
+ def file=: (String) -> String
25
+ # sig-gen gap: #1183 — as above.
26
+ def rule=: (String) -> String
27
+ # sig-gen gap: #1183 — as above.
28
+ def message_regex=: (Regexp?) -> Regexp?
29
+ # sig-gen gap: #1183 — as above.
30
+ def count=: (Integer) -> Integer
31
+ # sig-gen gap: #1183 — as above.
32
+ def self.new: (?file: String, ?rule: String, ?message_regex: Regexp?, ?count: Integer) -> instance
33
+ # sig-gen gap: #1183 — as above.
34
+ def self.[]: (?file: String, ?rule: String, ?message_regex: Regexp?, ?count: Integer) -> instance
35
+ end
36
+
37
+ # One bucket's drift state for `audit`. `status` is the four-way verdict `status_for` returns;
38
+ # `delta` is `actual_count - bucket.count` (positive = over threshold).
39
+ class DriftRow < ::Struct[untyped]
40
+ # sig-gen gap: #1183 — Struct member types are not inferred from construction sites; as above.
41
+ def bucket: () -> Bucket
42
+ # sig-gen gap: #1183 — as above.
43
+ def actual_count: () -> Integer
44
+ # sig-gen gap: #1183 — as above.
45
+ def status: () -> (:within | :over | :cleared | :reducible)
46
+ def delta: () -> Integer
47
+ # sig-gen gap: #1183 — as above.
48
+ def bucket=: (Bucket) -> Bucket
49
+ # sig-gen gap: #1183 — as above.
50
+ def actual_count=: (Integer) -> Integer
51
+ # sig-gen gap: #1183 — as above.
52
+ def status=: (:within | :over | :cleared | :reducible) -> (:within | :over | :cleared | :reducible)
53
+ # sig-gen gap: #1183 — as above.
54
+ def self.new: (?bucket: Bucket, ?actual_count: Integer, ?status: :within | :over | :cleared | :reducible) -> instance
55
+ # sig-gen gap: #1183 — as above.
56
+ def self.[]: (?bucket: Bucket, ?actual_count: Integer, ?status: :within | :over | :cleared | :reducible) -> instance
57
+ end
58
+
9
59
  # Load a baseline file from disk.
10
60
  # Returns `nil` when `path` is nil (no baseline configured).
11
61
  # Raises {LoadError} on malformed or unsupported content.
12
62
  def self.load: (::String? path, ?project_root: ::String) -> Baseline?
13
63
 
14
64
  # Build a baseline from a current run's diagnostic stream.
15
- def self.from_diagnostics: (untyped diagnostics, ?match_mode: :rule | :message) -> Baseline
65
+ def self.from_diagnostics: (untyped diagnostics, ?match_mode: :rule | :message, ?project_root: ::String | ::Pathname) -> Baseline
16
66
 
17
- attr_reader buckets: untyped
67
+ # Always an Array of Bucket — `initialize` freezes what it is given and every caller hands it
68
+ # Bucket instances (parse_row rows, from_diagnostics groups, `without`'s reject, or `[]`).
69
+ # sig-gen gap: #1154 — an `attr_reader` over an ivar assigned in `initialize` from a parameter
70
+ # is skipped (untyped return); the element type is hand-written.
71
+ attr_reader buckets: Array[Bucket]
18
72
 
19
- def initialize: (untyped buckets) -> void
73
+ # `project_root` is `Pathname.new`'d, so a `Pathname` is accepted as well as a `String`
74
+ # (`without` re-passes the stored Pathname).
75
+ def initialize: (Array[Bucket] buckets, ?project_root: ::String | ::Pathname) -> void
20
76
 
21
77
  # Apply the baseline filter. Returns [surfaced_diagnostics, silenced_count].
22
- def filter: (untyped diagnostics) -> [untyped, ::Integer]
78
+ # `diagnostics` stays `untyped`: `Analysis::Diagnostic`'s sig is partial (no `qualified_rule`),
79
+ # so a tighter param would put `diag.qualified_rule` behind an unsigned member. The declared
80
+ # `[Array[untyped], Integer]` diverges from sig-gen's inference
81
+ # (`[Array[untyped], untyped] | [untyped, 0]` — the literal seed and the accumulated local are
82
+ # unproven); the `Integer` count is the author's intent.
83
+ def filter: (untyped diagnostics) -> [Array[untyped], ::Integer]
23
84
 
24
- # Report bucket-level drift for each recorded baseline bucket.
25
- def audit: (untyped diagnostics) -> untyped
85
+ # Report bucket-level drift for each recorded baseline bucket — one DriftRow per bucket, in
86
+ # baseline-file order.
87
+ def audit: (untyped diagnostics) -> Array[DriftRow]
26
88
 
27
89
  # Return a new Baseline with the given buckets removed.
28
- def without: (untyped buckets_to_drop) -> Baseline
90
+ def without: (Array[Bucket] buckets_to_drop) -> Baseline
29
91
 
30
92
  # Serialise to a YAML string.
31
93
  def to_yaml: () -> ::String
@@ -2,7 +2,7 @@ module Rigor
2
2
  module Analysis
3
3
  module CheckRules
4
4
  def self?.diagnose: (path: String, root: untyped, scope_index: Hash[untyped, Scope]) -> Array[Diagnostic]
5
- def self?.build_node_collectors: (String path, untyped scope_index) -> Hash[Symbol, untyped]
5
+ def self?.build_node_collectors: (String path, untyped scope_index, ?untyped root) -> Hash[Symbol, untyped]
6
6
  def self?.node_collector_driver: (Hash[Symbol, untyped] collectors) -> untyped
7
7
  def self?.shadow_verify_converged_collectors: (String path, untyped root, untyped scope_index, Hash[Symbol, untyped]? collectors) -> void
8
8
  def self?.filter_suppressed: (Array[Diagnostic] diagnostics, comments: untyped, disabled_rules: Array[String]) -> Array[Diagnostic]
@@ -0,0 +1,74 @@
1
+ module Rigor
2
+ module Analysis
3
+ # Frozen snapshot of the project-wide pre-pass state the runner consumes — see
4
+ # lib/rigor/analysis/project_scan.rb for the full ownership/invalidation contract.
5
+ class ProjectScan < ::Data
6
+ # sig-gen gap: #1150 — `Data.define` member reads carry no type; `build_project_scan` fills
7
+ # this slot with the prepared `Plugin::Loader` result.
8
+ def plugin_registry: () -> Rigor::Plugin::Registry
9
+
10
+ # sig-gen gap: #1150 — as above (`DependencySourceInference::Builder.build` output, or
11
+ # `Index::EMPTY` when no dependencies are configured).
12
+ def dependency_source_index: () -> DependencySourceInference::Index
13
+
14
+ # `Inference::SyntheticMethodIndex` — the class is not yet declared under `sig/` (#1181
15
+ # backlog), so `untyped` is the honest member type for now.
16
+ def synthetic_method_index: () -> untyped
17
+
18
+ # `Inference::ProjectPatchedMethods` — unsigned like the slot above.
19
+ def project_patched_methods: () -> untyped
20
+
21
+ # sig-gen gap: #1150 — as above (`plugin_prepare_diagnostics` collects the
22
+ # `plugin_prepare_error_diagnostic` `Diagnostic`s, `[]` under pool mode).
23
+ def plugin_prepare_diagnostics: () -> Array[Analysis::Diagnostic]
24
+
25
+ # sig-gen gap: #1150 — as above. The pre-eval scanner deliberately emits a Hash shape (it
26
+ # must not depend on the analysis layer); the runner translates each row to a `Diagnostic`
27
+ # at the call site.
28
+ def pre_eval_diagnostics: () -> Array[{ path: String, line: Integer, column: Integer, severity: Symbol, rule: String, message: String }]
29
+
30
+ # `Analysis::TemplateUnits` — unsigned (#1181 backlog), kept `untyped`.
31
+ def template_units: () -> untyped
32
+
33
+ # sig-gen gap: #1150 — as above; constructor keywords mirror the member declarations.
34
+ def self.new: (
35
+ plugin_registry: Rigor::Plugin::Registry,
36
+ dependency_source_index: DependencySourceInference::Index,
37
+ synthetic_method_index: untyped,
38
+ project_patched_methods: untyped,
39
+ plugin_prepare_diagnostics: Array[Analysis::Diagnostic],
40
+ pre_eval_diagnostics: Array[{ path: String, line: Integer, column: Integer, severity: Symbol, rule: String, message: String }],
41
+ template_units: untyped
42
+ ) -> instance
43
+ | (
44
+ Rigor::Plugin::Registry plugin_registry,
45
+ DependencySourceInference::Index dependency_source_index,
46
+ untyped synthetic_method_index,
47
+ untyped project_patched_methods,
48
+ Array[Analysis::Diagnostic] plugin_prepare_diagnostics,
49
+ Array[{ path: String, line: Integer, column: Integer, severity: Symbol, rule: String, message: String }] pre_eval_diagnostics,
50
+ untyped template_units
51
+ ) -> instance
52
+
53
+ # sig-gen gap: #1150 — as above.
54
+ def self.[]: (
55
+ plugin_registry: Rigor::Plugin::Registry,
56
+ dependency_source_index: DependencySourceInference::Index,
57
+ synthetic_method_index: untyped,
58
+ project_patched_methods: untyped,
59
+ plugin_prepare_diagnostics: Array[Analysis::Diagnostic],
60
+ pre_eval_diagnostics: Array[{ path: String, line: Integer, column: Integer, severity: Symbol, rule: String, message: String }],
61
+ template_units: untyped
62
+ ) -> instance
63
+ | (
64
+ Rigor::Plugin::Registry plugin_registry,
65
+ DependencySourceInference::Index dependency_source_index,
66
+ untyped synthetic_method_index,
67
+ untyped project_patched_methods,
68
+ Array[Analysis::Diagnostic] plugin_prepare_diagnostics,
69
+ Array[{ path: String, line: Integer, column: Integer, severity: Symbol, rule: String, message: String }] pre_eval_diagnostics,
70
+ untyped template_units
71
+ ) -> instance
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,100 @@
1
+ module Rigor
2
+ module Effects
3
+ # `effects.envelopes:` entries resolved against the label vocabulary — the configured stratum of
4
+ # the envelope precedence (ADR-103 WD1).
5
+ module ConfigEnvelopes
6
+ CONFIG_PATH: String
7
+
8
+ # One entry, resolved against the vocabulary. `bound` is `LabelSet::TOP` when some member of
9
+ # `effect:` is unrecognised — the fail-open rule.
10
+ class Entry < ::Data
11
+ # sig-gen gap: #1150 — `Data.define` member reads carry no type; `build` proves each of these.
12
+ def index: () -> Integer
13
+
14
+ # sig-gen gap: #1150 — as above (path glob, or nil when `namespace:` is set).
15
+ def match: () -> String?
16
+
17
+ # sig-gen gap: #1150 — as above (constant-path glob, or nil when `match:` is set).
18
+ def namespace: () -> String?
19
+
20
+ # sig-gen gap: #1150 — as above (`LabelSet::TOP` on an unrecognised label).
21
+ def bound: () -> LabelSet
22
+
23
+ # sig-gen gap: #1150 — as above (the `effect:` list exactly as written).
24
+ def labels: () -> Array[String]
25
+
26
+ # sig-gen gap: #1150 — as above (well-formed spellings the registry did not know).
27
+ def unknown_labels: () -> Array[String]
28
+
29
+ # sig-gen gap: #1150 — as above; keyword form mirrors the member declarations.
30
+ def self.new: (
31
+ index: Integer,
32
+ match: String?,
33
+ namespace: String?,
34
+ bound: LabelSet,
35
+ labels: Array[String],
36
+ unknown_labels: Array[String]
37
+ ) -> instance
38
+ | (
39
+ Integer index,
40
+ String? match,
41
+ String? namespace,
42
+ LabelSet bound,
43
+ Array[String] labels,
44
+ Array[String] unknown_labels
45
+ ) -> instance
46
+
47
+ # sig-gen gap: #1150 — as above.
48
+ def self.[]: (
49
+ index: Integer,
50
+ match: String?,
51
+ namespace: String?,
52
+ bound: LabelSet,
53
+ labels: Array[String],
54
+ unknown_labels: Array[String]
55
+ ) -> instance
56
+ | (
57
+ Integer index,
58
+ String? match,
59
+ String? namespace,
60
+ LabelSet bound,
61
+ Array[String] labels,
62
+ Array[String] unknown_labels
63
+ ) -> instance
64
+
65
+ # `.rigor.yml effects.envelopes[N]` — the location spelling diagnostics name.
66
+ def location: () -> String
67
+
68
+ # The bound quoted back in the config's own spelling.
69
+ def spelling: () -> String
70
+
71
+ def top?: () -> bool
72
+ end
73
+
74
+ # `entries` are the shape-validated `Configuration#effects_envelopes` rows (String-keyed
75
+ # Hashes); `registry` is the `Effects::Registry` vocabulary — unsigned, so `untyped`.
76
+ def self?.build: (entries: Array[Hash[String, untyped]], registry: untyped) -> Array[Entry]
77
+
78
+ # One envelope per selected class, keyed by class name. `sources` is `Runner#effect_sources`'s
79
+ # shape; `project_root` is what those paths are relativised against.
80
+ def self?.for_classes: (
81
+ entries: Array[Entry],
82
+ class_names: Array[String],
83
+ ?sources: Hash[String, Array[String]],
84
+ ?project_root: String
85
+ ) -> Hash[String, Envelope]
86
+
87
+ # The {Envelope} one entry puts on one class.
88
+ def self?.envelope_for: (Entry entry, String class_name) -> Envelope
89
+
90
+ # Whether one entry selects a class — `paths` is `Array()`d, so `untyped` is honest.
91
+ def self?.selects?: (Entry entry, String class_name, untyped paths) -> bool
92
+
93
+ # `File.fnmatch?` with `FNM_PATHNAME` — the ADR-28 path-glob shape.
94
+ def self?.path_match?: (String glob, String path) -> bool
95
+
96
+ # Constant-path glob over the `::`-separated FQN; both arguments are `to_s`d.
97
+ def self?.namespace_match?: (untyped glob, untyped class_name) -> bool
98
+ end
99
+ end
100
+ end