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
@@ -0,0 +1,50 @@
1
+ module Rigor
2
+ module Effects
3
+ # One method's direct effect record: the labels its own body contributes, grouped by the origin
4
+ # that claimed them, plus the declared (`<=`) lane, the exhaustiveness bit, and the taint causes.
5
+ class Summary
6
+ TRIVIAL_BOUND: LabelSet
7
+
8
+ # The pure-modulo-frame-ownership summary: no origins, nothing declared, exhaustive, untainted.
9
+ def self.empty: () -> Summary
10
+
11
+ # A summary carrying a single taint and no labels — the fail-soft answer for a unit the collector
12
+ # could not finish.
13
+ def self.tainted: (String cause, ?String? detail) -> Summary
14
+
15
+ # sig-gen gap: #1154 — `initialize` normalizes the `bundles:`/`declared_bundles:` kwargs through
16
+ # `normalize_bundles` (join-merging per origin), so the readers do not trace to the parameters.
17
+ attr_reader bundles: Hash[Origin, LabelSet]
18
+ # sig-gen gap: #1154 — as above.
19
+ attr_reader declared_bundles: Hash[Origin, LabelSet]
20
+ # Unmarked residue — `proven`/`declared` are flattened from the bundle tables by `initialize`,
21
+ # not assigned from a parameter, so #1154 does not cover them (same shape as
22
+ # `Registry#additional_initializers`).
23
+ attr_reader declared: LabelSet
24
+ attr_reader proven: LabelSet
25
+ # sig-gen gap: #1154 — `causes` are `[cause, detail]` pairs normalized in `initialize`.
26
+ attr_reader causes: Array[[String, String?]]
27
+
28
+ def initialize: (?bundles: Hash[Origin, LabelSet], ?declared_bundles: Hash[Origin, LabelSet],
29
+ ?exhaustive: bool, ?causes: Array[[String, String?]], ?unclaimed: bool) -> void
30
+
31
+ # Whether every call this method makes was resolved.
32
+ def exhaustive?: () -> bool
33
+
34
+ # Whether this method made a call nothing described — read by `rigor sig-gen`'s annotation
35
+ # emission alone (#391).
36
+ def unclaimed?: () -> bool
37
+
38
+ # Whether the report omits this row by default (#386).
39
+ def trivial?: () -> bool
40
+
41
+ # Union in every lane — reopenings and multi-file contributors fold through this.
42
+ def join: (Summary other) -> Summary
43
+
44
+ def ==: (untyped other) -> bool
45
+ alias eql? ==
46
+ def hash: () -> Integer
47
+ def inspect: () -> String
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,12 @@
1
+ module Rigor
2
+ module Effects
3
+ # The closed enum of reasons a summary is not exhaustive (ADR-103 WD14). A reporting vocabulary,
4
+ # never a diagnostic one.
5
+ module TaintCause
6
+ ALL: Array[String]
7
+
8
+ # `cause.to_s` is looked up, so any object is a fair question.
9
+ def self?.valid?: (untyped cause) -> bool
10
+ end
11
+ end
12
+ end
@@ -15,10 +15,8 @@ module Rigor
15
15
  attr_reader hkt_registry: untyped?
16
16
  # Issue #784 — `[error_class_name, first_message_line, raw_frame_or_nil, stage]` when either stage of
17
17
  # the HKT-registry build raised at its seam (`:scan`, the RBS `type`-alias scan; `:overlay`, the
18
- # plugin-manifest aggregation — #791), nil when both built or were never demanded. Declared `untyped?`
19
- # like its neighbours:
20
- # `rigor sig-gen` emits nothing for this delegating reader, and the tuple shape is documented here.
21
- def hkt_scan_failure: () -> untyped?
18
+ # plugin-manifest aggregation — #791), nil when both built or were never demanded.
19
+ def hkt_scan_failure: () -> [String, String, String?, Symbol]?
22
20
 
23
21
  def self.default: () -> Environment
24
22
  def self.for_project: (?root: String, ?libraries: Array[String], ?signature_paths: Array[String | _ToPath]?, ?cache_store: untyped?, ?plugin_registry: untyped?, ?dependency_source_index: untyped?, ?rbs_extended_reporter: untyped?, ?boundary_cross_reporter: untyped?, ?source_rbs_synthesis_reporter: untyped?, ?bundler_bundle_path: String?, ?bundler_auto_detect: bool, ?synthetic_method_index: untyped?, ?project_patched_methods: untyped?) -> Environment
@@ -31,6 +29,9 @@ module Rigor
31
29
  def nominal_for_name: (String | Symbol name) -> Type::Nominal?
32
30
  def singleton_for_name: (String | Symbol name) -> Type::Singleton?
33
31
  def constant_for_name: (String | Symbol name) -> Type::t?
32
+ # sig-gen gap: #1154 — the answer comes through `rbs_loader`, an `attr_reader` over an ivar assigned in
33
+ # `initialize` from a parameter, which reaches `untyped`.
34
+ def global_for_name: (String | Symbol name, ?builtin: bool) -> Type::t?
34
35
  def class_known?: (String | Symbol name) -> bool
35
36
  def rbs_module?: (String | Symbol name) -> bool
36
37
  def singleton_extended_modules: (String | Symbol name) -> Array[String]
@@ -59,7 +60,7 @@ module Rigor
59
60
 
60
61
  def self.default: () -> RbsLoader
61
62
  def self.reset_default!: () -> void
62
- def self.build_env_for: (libraries: Array[String], signature_paths: Array[String | _ToPath]) -> untyped
63
+ def self.build_env_for: (libraries: Array[String], signature_paths: Array[String | _ToPath]) -> ::RBS::Environment
63
64
  def self.vendored_gem_sig_paths: () -> Array[Pathname]
64
65
  def self.capability_role_sig_paths: () -> ([Pathname] | [])
65
66
  def self.vendored_gem_names: () -> Array[String]
@@ -67,10 +68,10 @@ module Rigor
67
68
  def initialize: (?libraries: Array[String], ?signature_paths: Array[String | _ToPath], ?cache_store: untyped?) -> void
68
69
  def class_known?: (String | Symbol name) -> bool
69
70
  def rbs_module?: (String | Symbol name) -> bool
70
- def instance_definition: (String | Symbol class_name) -> untyped?
71
- def instance_method: (class_name: String | Symbol, method_name: String | Symbol) -> untyped?
72
- def singleton_definition: (String | Symbol class_name) -> untyped?
73
- def singleton_method: (class_name: String | Symbol, method_name: String | Symbol) -> untyped?
71
+ def instance_definition: (String | Symbol class_name) -> ::RBS::Definition?
72
+ def instance_method: (class_name: String | Symbol, method_name: String | Symbol) -> ::RBS::Definition::Method?
73
+ def singleton_definition: (String | Symbol class_name) -> ::RBS::Definition?
74
+ def singleton_method: (class_name: String | Symbol, method_name: String | Symbol) -> ::RBS::Definition::Method?
74
75
  def class_type_param_names: (String | Symbol class_name) -> Array[Symbol]
75
76
  def project_declared_classes: () -> Set[String]
76
77
  def project_declared_class?: (String | Symbol class_name) -> bool
@@ -79,7 +80,8 @@ module Rigor
79
80
  def singleton_extended_module_names: (String | Symbol class_name) -> Array[String]
80
81
  def constant_type: (String name) -> Type::t?
81
82
  def constant_names: () -> Array[String]
82
- def each_known_class_name: () { (String name) -> void } -> untyped
83
+ def each_known_class_name: () { (String name) -> void } -> void
84
+ | () -> ::Enumerator[String, void]
83
85
  end
84
86
 
85
87
  class RbsHierarchy
@@ -0,0 +1,10 @@
1
+ module Rigor
2
+ module Inference
3
+ module OptimisticOrigin
4
+ # sig-gen gap: #1150 — sig-gen types the `BoundMark#miss` member read `untyped`, so it skips this reader
5
+ # (sig.skipped.untyped-return). The answer is the recorded `true` / `false` / `nil`, or the `UNKNOWN_MISS`
6
+ # sentinel; declaring it is what lets sig-gen type `Scope#optimistic_local_miss` / `#optimistic_ivar_miss`.
7
+ def self?.bound_miss: (untyped mark) -> Object?
8
+ end
9
+ end
10
+ end
@@ -23,8 +23,10 @@ module Rigor
23
23
  class ClassFrame
24
24
  attr_reader name: String
25
25
  attr_reader singleton: bool
26
- def self.new: (name: String, singleton: bool) -> ClassFrame
27
- def initialize: (name: String, singleton: bool) -> void
26
+ # sig-gen gap: #1150 — `Data.define` members carry no type.
27
+ attr_reader refinement: bool
28
+ def self.new: (name: String, singleton: bool, ?refinement: bool) -> ClassFrame
29
+ def initialize: (name: String, singleton: bool, ?refinement: bool) -> void
28
30
  end
29
31
 
30
32
  def initialize: (scope: Scope, ?tracer: FallbackTracer?, ?on_enter: (^(untyped, Scope) -> void)?, ?class_context: Array[ClassFrame]) -> void
@@ -113,7 +115,7 @@ module Rigor
113
115
  def self?.value_pattern_certainty: (Type::t subject_type, untyped pattern_value) -> (:yes | :no | :maybe)
114
116
  def self?.predicate_scopes: (untyped node, Scope scope) -> [Scope, Scope]
115
117
  def self?.case_when_scopes: (untyped subject, Array[untyped] conditions, Scope scope) -> [Scope, Scope]
116
- def self?.analyse: (untyped node, Scope scope) -> untyped
118
+ def self?.analyse: (untyped node, Scope scope) -> [Scope, Scope]?
117
119
  def self?.subclass_of?: (String rigor_class_name, String target_class_name, untyped context) -> bool
118
120
  def self?.class_ordering: (String lhs, String rhs, untyped context) -> Symbol
119
121
  def self?.trusted_equality_literal?: (untyped literal) -> bool
@@ -170,7 +172,7 @@ module Rigor
170
172
  def self?.collect_class_decls: (untyped node, Array[String] qualified_prefix, Hash[String, Type::t] accumulator) -> void
171
173
  def self?.constant_writes_for_file: (untyped root) -> Hash[String, untyped]
172
174
  def self?.constant_literal_value: (untyped rvalue) -> Array[untyped]?
173
- def self?.finalize_constant_writes: (Hash[String, Hash[String, untyped]] writes) -> [Hash[String, Type::t], Hash[String, Set[String]]]
175
+ def self?.finalize_constant_writes: (Hash[String, Hash[String, untyped]] writes) -> [Hash[String, Type::Constant], Hash[String, Set[String]]]
174
176
  def self?.propagate: (untyped node, Hash[untyped, Scope] table, Scope parent_scope) -> void
175
177
  end
176
178
 
@@ -0,0 +1,36 @@
1
+ module Rigor
2
+ module Plugin
3
+ # ADR-38 declaration — methods/def-blocks that establish ivar state like `initialize` does, so
4
+ # the read-before-write nil soundness gate does not widen their ivars. See
5
+ # lib/rigor/plugin/additional_initializer.rb for the full contract.
6
+ class AdditionalInitializer
7
+ # sig-gen gap: #1154 — `attr_reader` rows over ivars assigned from `initialize` parameters are
8
+ # skipped (untyped return); the constructor validates `receiver_constraint` is a non-empty
9
+ # String and normalizes both lists with `map(&:to_sym)`, so the stored types are hand-written.
10
+ attr_reader receiver_constraint: String
11
+
12
+ # sig-gen gap: #1154 — as above.
13
+ attr_reader methods: Array[Symbol]
14
+
15
+ # sig-gen gap: #1154 — as above.
16
+ attr_reader block_methods: Array[Symbol]
17
+
18
+ # The validators accept Symbol or non-empty String elements; `initialize` normalizes to
19
+ # Symbol before storing. At least one of `methods:`/`block_methods:` must be non-empty.
20
+ def initialize: (receiver_constraint: String, ?methods: Array[Symbol | String], ?block_methods: Array[Symbol | String]) -> void
21
+
22
+ def covers_method?: (Symbol method_name) -> bool
23
+
24
+ def covers_block_method?: (Symbol method_name) -> bool
25
+
26
+ def to_h: () -> Hash[String, String | Array[String]]
27
+
28
+ def ==: (untyped other) -> bool
29
+
30
+ # `alias eql? ==` — the alias row has no sig-gen shape, so it stays unmarked residue.
31
+ def eql?: (untyped other) -> bool
32
+
33
+ def hash: () -> Integer
34
+ end
35
+ end
36
+ end
@@ -17,11 +17,11 @@ class Rigor::Plugin::Base
17
17
  def self.producer: (untyped id, ?watch: untyped, ?serialize: untyped, ?deserialize: untyped, ?generation_cap: untyped) { (untyped params) -> untyped } -> Symbol
18
18
  def self.producers: () -> Hash[Symbol, untyped]
19
19
 
20
- def self.node_rule: (untyped node_type) { (*untyped) -> untyped } -> untyped
20
+ def self.node_rule: (untyped node_type) { (*untyped) -> untyped } -> Class
21
21
  def self.node_rules: () -> Array[untyped]
22
22
 
23
- def self.node_file_context: () { (untyped root, untyped scope) -> untyped } -> untyped
24
- def self.node_file_context_block: () -> untyped
23
+ def self.node_file_context: () { (untyped root, untyped scope) -> untyped } -> void
24
+ def self.node_file_context_block: () -> (^(untyped root, untyped scope) -> untyped)?
25
25
 
26
26
  def self.dynamic_return: (?receivers: (Array[String] | ^() -> Array[String])?, ?methods: (Array[untyped] | ^() -> Array[untyped])?, ?file_methods: (^(untyped path) -> Array[untyped])?) { (untyped call_node, untyped scope) -> untyped } -> nil
27
27
  def self.dynamic_returns: () -> Array[untyped]
@@ -44,22 +44,45 @@ class Rigor::Plugin::Base
44
44
  def init: (untyped services) -> nil
45
45
  def prepare: (untyped services) -> nil
46
46
  def diagnostics_for_file: (path: untyped, scope: untyped, root: untyped) -> Array[untyped]
47
+ # authored: hook-contract widening — the element type comes from a plugin gem sig-gen never
48
+ # sees, so no engine work would let it answer; the declared `Array[Rigor::Plugin::TemplateUnit]`
49
+ # over a bare-`[]` default body is the author's contract.
50
+ def template_units_for_file: (path: untyped, source: untyped) -> Array[untyped]
51
+ # authored: hook-contract widening — the element type comes from a plugin gem sig-gen never
52
+ # sees, so no engine work would let it answer; the declared record contract over a bare-`[]`
53
+ # default body is the author's.
54
+ def declared_members: (untyped class_name) -> Array[untyped]
47
55
 
48
56
  # Engine-executed dispatch over the declared DSLs.
49
57
  def node_rule_diagnostics: (path: untyped, scope: untyped, root: untyped) -> Array[untyped]
50
- def dynamic_return_type: (call_node: untyped, scope: untyped, receiver_type: untyped) -> untyped
58
+ # sig-gen gap: #1007 — the true `return result if result` branch (base.rb:594) flows through an
59
+ # `instance_exec`'d, plugin-supplied Proc that sig-gen's inference does not fold into the return
60
+ # join, so it proposes the literal fallback `nil` instead of the honest contract.
61
+ def dynamic_return_type: (call_node: untyped, scope: untyped, receiver_type: untyped) -> Rigor::Type::t?
51
62
  def narrowing_facts_for: (call_node: untyped, scope: untyped) -> Array[untyped]
52
63
 
53
64
  # Authoring helpers.
54
- def diagnostic: (untyped node, path: untyped, message: untyped, ?severity: untyped, ?rule: untyped, ?location: untyped) -> untyped
65
+ def diagnostic: (untyped node, path: untyped, message: untyped, ?severity: untyped, ?rule: untyped, ?location: untyped) -> Rigor::Analysis::Diagnostic
55
66
  def diagnostics_for: (untyped violations, path: untyped, ?node: untyped) -> Array[untyped]
56
67
  def read_fact: (plugin_id: untyped, name: untyped) -> untyped
57
68
  def producer_value: (untyped id, ?params: untyped) -> untyped
58
69
  def producer_error: (untyped id) -> untyped
70
+ def disclose_once: (untyped key, message: untyped, ?severity: untyped, ?rule: untyped) -> nil
71
+ def emit_once: (untyped key, untyped diagnostics) -> nil
72
+ def run_disclosure_records: () -> Array[untyped]
59
73
  def manifest: () -> Rigor::Plugin::Manifest
60
74
  def signature_paths: () -> Array[String]
61
- def protocol_contracts: () -> untyped
75
+ # Defaults to `manifest.protocol_contracts`; a plugin MAY override to fold per-project config in,
76
+ # but the contract (an Array of ProtocolContract) holds either way.
77
+ def protocol_contracts: () -> Array[Rigor::Plugin::ProtocolContract]
78
+ # The ADR-103 effect surfaces delegate to the manifest by default; a plugin MAY override
79
+ # `effect_attributions` to fold per-project config in, but the contract holds either way.
80
+ def effect_labels: () -> Array[String]
81
+ def effect_attributions: () -> Array[Rigor::Plugin::EffectAttribution]
82
+ def effect_edges: () -> Array[Rigor::Plugin::EffectEdge]
83
+ def effect_entry_points: () -> Array[Rigor::Plugin::EffectEntryPoints]
84
+ def effect_ancestry: () -> Array[Rigor::Plugin::EffectAncestry]
62
85
  def io_boundary: () -> Rigor::Plugin::IoBoundary
63
- def cache_for: (untyped producer_id, ?params: untyped, ?descriptor: untyped) -> untyped
86
+ def cache_for: (untyped producer_id, ?params: untyped, ?descriptor: untyped) -> Proc
64
87
  def plugin_entry: () -> untyped
65
88
  end
@@ -0,0 +1,27 @@
1
+ module Rigor
2
+ module Plugin
3
+ # One `effect_ancestry:` row: an ancestry edge the plugin's own gem introduces and the project's
4
+ # source never writes down (ADR-103 WD17, #465). `parent:` need only be a true ancestor, not the
5
+ # immediate superclass. Bundled plugins only — `Effects::PluginFacts` enforces it. Frozen value
6
+ # object.
7
+ class EffectAncestry
8
+ # sig-gen gap: #1154 — validated in `initialize` from the parameter of the same name
9
+ # (`to_s`-normalized, frozen), so sig-gen proposes the raw parameter shape.
10
+ attr_reader child: String
11
+ # sig-gen gap: #1154 — same shape as `child`.
12
+ attr_reader parent: String
13
+ # sig-gen gap: #1154 — same shape; `why:` is required and validated non-empty.
14
+ attr_reader why: String
15
+
16
+ def initialize: (child: untyped, parent: untyped, why: untyped) -> void
17
+
18
+ def to_h: () -> Hash[String, untyped]
19
+
20
+ def ==: (untyped other) -> bool
21
+ # `alias eql? ==` — the alias row has no sig-gen shape, so it stays unmarked
22
+ # residue.
23
+ def eql?: (untyped other) -> bool
24
+ def hash: () -> Integer
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,66 @@
1
+ module Rigor
2
+ module Plugin
3
+ # One `effect_attributions:` row: the receiver spelling, the selector, and the labels the call
4
+ # contributes to the declared lane — plus the optional `narrow:`/`callee:`/`taint:`/`responds:`
5
+ # modifiers the engine owns the strategy for (#393/#1048/#1065). Frozen value object.
6
+ class EffectAttribution
7
+ # A receiver spelled as a `Constant::Path` — the class-name form.
8
+ CLASS_NAME: Regexp
9
+ # A receiver path: a constant head followed by one or more sends (`Rails.cache`).
10
+ RECEIVER_PATH: Regexp
11
+ # A self path: implicit self followed by one or more receiver-less sends (`self.flash.now`).
12
+ SELF_PATH: Regexp
13
+ # What a self path is rooted at, once the `self.` head is stripped.
14
+ SELF_HEAD: String
15
+ # The taint causes a plugin row may name — a closed subset of `Effects::TaintCause::ALL`.
16
+ TAINT_CAUSES: Array[String]
17
+
18
+ # sig-gen gap: #1154 — normalized/validated in `initialize` from the parameter of the same
19
+ # name (`to_s`-coerced, frozen), so sig-gen proposes the raw parameter shape.
20
+ attr_reader receiver: String
21
+ # sig-gen gap: #1154 — `to_sym`-normalized from the `method:` parameter.
22
+ attr_reader method: Symbol
23
+ attr_reader singleton: bool
24
+ # sig-gen gap: #1154 — `Array()`-normalized, deduplicated and frozen from `labels:`.
25
+ attr_reader labels: Array[String]
26
+ # sig-gen gap: #1154 — `to_s`-normalized from the `narrow:` parameter.
27
+ attr_reader narrow: String?
28
+ attr_reader discharge: bool
29
+ # sig-gen gap: #1154 — `to_s`-normalized from the `within:` parameter.
30
+ attr_reader within: String?
31
+ attr_reader on_result: bool
32
+ # sig-gen gap: #1154 — `to_s`-normalized from the `taint:` parameter.
33
+ attr_reader taint: String?
34
+ # sig-gen gap: #1154 — `to_s`-normalized from the `callee:` parameter.
35
+ attr_reader callee: String?
36
+ # sig-gen gap: #1154 — normalized from the `callee_fallbacks:` parameter.
37
+ attr_reader callee_fallbacks: Hash[String, Array[String]]?
38
+ attr_reader responds: bool
39
+ # sig-gen gap: #1154 — `to_s`-normalized from the `why:` parameter.
40
+ attr_reader why: String
41
+
42
+ # The coercion-facing constructor: every parameter is `to_s`/`to_sym`/`Array()`-normalized,
43
+ # so `untyped` is the honest parameter type throughout.
44
+ def initialize: (receiver: untyped, method: untyped, labels: untyped, why: untyped,
45
+ ?singleton: untyped, ?narrow: untyped, ?discharge: untyped,
46
+ ?within: untyped, ?on_result: untyped, ?taint: untyped, ?callee: untyped,
47
+ ?callee_fallbacks: untyped, ?responds: untyped) -> void
48
+
49
+ # Whether {#receiver} is a receiver path (`Rails.cache`) rather than a class name or a
50
+ # self path.
51
+ def receiver_path?: () -> bool
52
+ # Whether {#receiver} is a self path (`self.flash.now`).
53
+ def self_path?: () -> bool
54
+
55
+ # The key an origin and a report spell this row as.
56
+ def key: () -> String
57
+ def to_h: () -> Hash[String, untyped]
58
+
59
+ def ==: (untyped other) -> bool
60
+ # `alias eql? ==` — the alias row has no sig-gen shape, so it stays unmarked
61
+ # residue.
62
+ def eql?: (untyped other) -> bool
63
+ def hash: () -> Integer
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,33 @@
1
+ module Rigor
2
+ module Plugin
3
+ # One `effect_edges:` row: a framework-edge strategy naming the base `receiver` a plugin points
4
+ # the engine at, the `target` strategy slot, and an optional method-level `selector`. Frozen
5
+ # value object.
6
+ class EffectEdge
7
+ # The closed set of framework-edge strategies the engine implements.
8
+ TARGETS: Array[Symbol]
9
+
10
+ # sig-gen gap: #1154 — validated/normalized in `initialize` from the parameter of the same
11
+ # name, so sig-gen proposes the raw parameter shape.
12
+ attr_reader receiver: String
13
+ # sig-gen gap: #1154 — `to_sym`-normalized from the `method:` parameter.
14
+ attr_reader method: Symbol?
15
+ attr_reader singleton: bool
16
+ # sig-gen gap: #1154 — validated against `TARGETS` in `initialize`.
17
+ attr_reader target: (:activerecord_callbacks | :perform_now | :mailer_body)
18
+ # sig-gen gap: #1154 — `to_s`-normalized from the `why:` parameter.
19
+ attr_reader why: String
20
+
21
+ def initialize: (receiver: untyped, target: untyped, why: untyped, ?method: untyped,
22
+ ?singleton: untyped) -> void
23
+
24
+ def to_h: () -> Hash[String, untyped]
25
+
26
+ def ==: (untyped other) -> bool
27
+ # `alias eql? ==` — the alias row has no sig-gen shape, so it stays unmarked
28
+ # residue.
29
+ def eql?: (untyped other) -> bool
30
+ def hash: () -> Integer
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,25 @@
1
+ module Rigor
2
+ module Plugin
3
+ # One `effect_entry_points:` row: a named set of globs marking project files whose methods are
4
+ # framework entry points (ADR-103 WD6). Frozen value object; {#globs} are deduplicated and
5
+ # sorted in `initialize`.
6
+ class EffectEntryPoints
7
+ # sig-gen gap: #1154 — `to_s`-normalized in `initialize` from the `name:` parameter.
8
+ attr_reader name: String
9
+ # sig-gen gap: #1154 — deduplicated/sorted/frozen in `initialize` from `globs:`.
10
+ attr_reader globs: Array[String]
11
+ # sig-gen gap: #1154 — `to_s`-normalized in `initialize` from `why:`.
12
+ attr_reader why: String
13
+
14
+ def initialize: (name: untyped, globs: untyped, ?why: untyped) -> void
15
+
16
+ def to_h: () -> Hash[String, untyped]
17
+
18
+ def ==: (untyped other) -> bool
19
+ # `alias eql? ==` — the alias row has no sig-gen shape, so it stays unmarked
20
+ # residue.
21
+ def eql?: (untyped other) -> bool
22
+ def hash: () -> Integer
23
+ end
24
+ end
25
+ end
@@ -4,7 +4,7 @@ class Rigor::Plugin::IoBoundary
4
4
  def file?: (untyped) -> bool
5
5
  def directory?: (untyped) -> bool
6
6
  def list_directory: (untyped) -> Array[String]
7
- # sig-gen gap: #959 — the generator pins the empty-summary literal (`count: 0, first_path: nil`); the
7
+ # sig-gen gap: #1156 — the generator pins the empty-summary literal (`count: 0, first_path: nil`); the
8
8
  # record's fields are the running count and the first refused path, nil when nothing was refused.
9
9
  def refusal_summary: () -> { count: Integer, first_path: String?, nearest_root: String? }?
10
10
  def open_url: (untyped url) -> String
@@ -12,9 +12,9 @@ module Rigor
12
12
  attr_reader services: untyped
13
13
  attr_reader requirer: ^(String) -> untyped
14
14
 
15
- def self.load: (configuration: Configuration, services: untyped, ?requirer: ^(String) -> untyped) -> untyped
16
- def initialize: (services: untyped, ?requirer: ^(String) -> untyped) -> void
17
- def load: (Array[String | Hash[untyped, untyped]] entries) -> untyped
15
+ def self.load: (configuration: Configuration, services: untyped, ?requirer: ^(String) -> untyped, ?feature_resolver: untyped) -> Registry
16
+ def initialize: (services: untyped, ?requirer: ^(String) -> untyped, ?feature_resolver: untyped) -> void
17
+ def load: (Array[String | Hash[untyped, untyped]] entries) -> Registry
18
18
  end
19
19
  end
20
20
  end
@@ -3,35 +3,74 @@ class Rigor::Plugin::Manifest::Consumption
3
3
  end
4
4
 
5
5
  class Rigor::Plugin::Manifest
6
- def initialize: (id: untyped, version: untyped, ?description: untyped, ?config_schema: untyped, ?target_gems: untyped, ?produces: untyped, ?consumes: untyped, ?owns_receivers: untyped, ?open_receivers: untyped, ?type_node_resolvers: untyped, ?block_as_methods: untyped, ?heredoc_templates: untyped, ?nested_class_templates: untyped, ?trait_registries: untyped, ?hkt_registrations: untyped, ?hkt_definitions: untyped, ?signature_paths: untyped, ?protocol_contracts: untyped, ?source_rbs_synthesizer: untyped, ?additional_initializers: untyped) -> void
6
+ def initialize: (id: untyped, version: untyped, ?description: untyped, ?config_schema: untyped, ?target_gems: untyped, ?produces: untyped, ?consumes: untyped, ?owns_receivers: untyped, ?open_receivers: untyped, ?rbs_complete_ancestors: untyped, ?type_node_resolvers: untyped, ?block_as_methods: untyped, ?heredoc_templates: untyped, ?nested_class_templates: untyped, ?trait_registries: untyped, ?hkt_registrations: untyped, ?hkt_definitions: untyped, ?signature_paths: untyped, ?protocol_contracts: Array[Rigor::Plugin::ProtocolContract], ?source_rbs_synthesizer: untyped, ?additional_initializers: Array[Rigor::Plugin::AdditionalInitializer], ?effect_root: String?, ?effect_labels: Array[String], ?effect_attributions: Array[Rigor::Plugin::EffectAttribution], ?effect_edges: Array[Rigor::Plugin::EffectEdge], ?effect_entry_points: Array[Rigor::Plugin::EffectEntryPoints], ?effect_ancestry: Array[Rigor::Plugin::EffectAncestry], ?template_globs: untyped) -> void
7
7
 
8
8
  # Public attribute readers (the full `attr_reader` surface). Plugins
9
9
  # read `manifest.id` / `manifest.protocol_contracts` etc.; declaring
10
10
  # them keeps the contract surface resolvable so ADR-43 ancestor
11
11
  # resolution does not surface a false `call.undefined-method` on a
12
- # real reader. Identity fields are typed; the structured slots stay
13
- # `untyped` per the sparse `sig/` tree.
12
+ # real reader. Slots whose element classes are sig-covered carry the
13
+ # validated element type (the `validate_*!` constructors prove it);
14
+ # the rest stay `untyped` per the sparse `sig/` tree.
14
15
  def id: () -> String
15
16
  def version: () -> String
16
17
  def description: () -> String?
17
18
  def config_schema: () -> untyped
18
19
  def config_defaults: () -> Hash[String, untyped]
19
20
  def target_gems: () -> Array[String]
20
- def produces: () -> untyped
21
- def consumes: () -> untyped
22
- def owns_receivers: () -> untyped
23
- def open_receivers: () -> untyped
24
- def type_node_resolvers: () -> untyped
21
+ # sig-gen gap: #1154 — an `attr_reader` over an ivar assigned in `initialize` from a parameter the
22
+ # manifest validates but does not type, so inference reaches `untyped` where the contract is
23
+ # `Array[String]` (the same gap every other reader in this block carries).
24
+ def template_globs: () -> Array[String]
25
+ def produces: () -> Array[Symbol]
26
+ def consumes: () -> Array[Rigor::Plugin::Manifest::Consumption]
27
+ def owns_receivers: () -> Array[String]
28
+ def open_receivers: () -> Array[String]
29
+ def rbs_complete_ancestors: () -> Array[String]
30
+ def type_node_resolvers: () -> Array[Rigor::Plugin::TypeNodeResolver]
25
31
  def block_as_methods: () -> untyped
26
32
  def heredoc_templates: () -> untyped
27
33
  def nested_class_templates: () -> untyped
28
34
  def trait_registries: () -> untyped
29
35
  def hkt_registrations: () -> untyped
30
36
  def hkt_definitions: () -> untyped
31
- def signature_paths: () -> untyped
32
- def protocol_contracts: () -> untyped
37
+ def signature_paths: () -> Array[String]
38
+ # sig-gen gap: #1154 — `attr_reader` over an ivar assigned in `initialize` from a parameter;
39
+ # `validate_protocol_contracts!` requires every element `is_a?(ProtocolContract)`.
40
+ def protocol_contracts: () -> Array[Rigor::Plugin::ProtocolContract]
41
+ # ADR-32 WD6/WD12 — any object responding to `call`, and its result is a documented multi-shape
42
+ # outcome (`String` / nil / `[:error, msg]` / `[:ok, src, msgs]`), not `String?` — `untyped` is the
43
+ # honest claim until the outcome has a sig'd shape.
33
44
  def source_rbs_synthesizer: () -> untyped
34
- def additional_initializers: () -> untyped
45
+ # sig-gen gap: #1154 — `attr_reader` over an ivar assigned in `initialize` from a parameter;
46
+ # the validator (`validate_additional_initializers!`) requires every element
47
+ # `is_a?(AdditionalInitializer)`, so the element type is hand-written.
48
+ def additional_initializers: () -> Array[Rigor::Plugin::AdditionalInitializer]
49
+
50
+ # sig-gen gap: #1154 — `attr_reader` over an ivar assigned in `initialize` from a parameter
51
+ # (`to_s`-normalized); `validate_effect_root!` bounds the spelling.
52
+ def effect_root: () -> String?
53
+ # sig-gen gap: #1154 — `attr_reader` over an ivar normalized in `initialize` from a parameter;
54
+ # `validate_effect_labels!` requires non-empty `String` elements.
55
+ def effect_labels: () -> Array[String]
56
+ # sig-gen gap: #1154 — `attr_reader` over an ivar assigned in `initialize` from a parameter;
57
+ # `validate_effect_attributions!` requires every element `is_a?(EffectAttribution)`.
58
+ def effect_attributions: () -> Array[Rigor::Plugin::EffectAttribution]
59
+ # sig-gen gap: #1154 — same shape; `validate_effect_edges!` requires `is_a?(EffectEdge)`.
60
+ def effect_edges: () -> Array[Rigor::Plugin::EffectEdge]
61
+ # sig-gen gap: #1154 — same shape; `validate_effect_entry_points!` requires
62
+ # `is_a?(EffectEntryPoints)`.
63
+ def effect_entry_points: () -> Array[Rigor::Plugin::EffectEntryPoints]
64
+ # sig-gen gap: #1154 — same shape; `validate_effect_ancestry!` requires `is_a?(EffectAncestry)`.
65
+ def effect_ancestry: () -> Array[Rigor::Plugin::EffectAncestry]
66
+
67
+ # The identity opening a root when this plugin's labels join the run's vocabulary: the
68
+ # `effect_root` for a bundled first-party plugin that declares one, the plugin `id` otherwise.
69
+ def effect_owner: () -> String
70
+ # Whether this plugin's `effect_attributions:` may carry `discharge: true` (ADR-103 WD6).
71
+ def effect_discharge_allowed?: () -> bool
72
+ # Whether the plugin contributes anything to the effect surfaces at all.
73
+ def effects?: () -> bool
35
74
 
36
75
  def validate_config: (untyped) -> Array[String]
37
76
  def to_h: () -> Hash[String, untyped]
@@ -0,0 +1,68 @@
1
+ module Rigor
2
+ module Plugin
3
+ # ADR-28 declaration — "every instance/singleton method named `method_name` in a file matching
4
+ # `path_glob` carries the declared parameter + return-type protocol" (provide-and-check). See
5
+ # lib/rigor/plugin/protocol_contract.rb for the full contract.
6
+ class ProtocolContract
7
+ VALID_SEVERITIES: Array[Symbol]
8
+
9
+ # One positional-parameter provision: zero-based index + fully-qualified type name.
10
+ class ParamType < ::Data
11
+ # sig-gen gap: #1150 — `Data.define` member reads carry no type; `coerce_param_type` proves
12
+ # `index` is a non-negative Integer and `type_name` a non-empty String, so the member rows
13
+ # are hand-written.
14
+ def index: () -> Integer
15
+
16
+ # sig-gen gap: #1150 — as above.
17
+ def type_name: () -> String
18
+
19
+ # sig-gen gap: #1150 — as above.
20
+ def self.new: (index: Integer, type_name: String) -> instance | (Integer index, String type_name) -> instance
21
+
22
+ # sig-gen gap: #1150 — as above.
23
+ def self.[]: (index: Integer, type_name: String) -> instance | (Integer index, String type_name) -> instance
24
+ end
25
+
26
+ # sig-gen gap: #1154 — `attr_reader` rows over ivars assigned in `initialize`; each is
27
+ # validated/normalized first (`dup.freeze`/`to_sym`/truthiness collapse/coerce), so the
28
+ # stored types are hand-written.
29
+ attr_reader path_glob: String
30
+
31
+ # sig-gen gap: #1154 — as above (`to_sym` normalizes the accepted Symbol|String).
32
+ attr_reader method_name: Symbol
33
+
34
+ # `singleton ? true : false` collapses any truthy input to bool — sig-gen already infers
35
+ # `false | true`, so this row is generated-equivalent rather than a #1154 gap.
36
+ attr_reader singleton: bool
37
+
38
+ # sig-gen gap: #1154 — as above (`coerce_param_types` guarantees `Array[ParamType]`).
39
+ attr_reader param_types: Array[ParamType]
40
+
41
+ # sig-gen gap: #1154 — as above (nil or a non-empty `dup.freeze`d String).
42
+ attr_reader return_type_name: String?
43
+
44
+ # sig-gen gap: #1154 — as above (`VALID_SEVERITIES.include?(to_sym)` bounds the stored value
45
+ # to the three declared literals).
46
+ attr_reader severity: :error | :warning | :info
47
+
48
+ # `method_name`/`severity` accept String too (both are `to_sym`'d); `param_types` entries are
49
+ # ParamType or a Hash with `index`/`type_name` keys (String or Symbol keys accepted by the
50
+ # coercion). `singleton` is documented Boolean; the impl collapses any truthy value.
51
+ def initialize: (path_glob: String, method_name: Symbol | String, ?return_type_name: String?, ?param_types: Array[ParamType | Hash[untyped, untyped]], ?singleton: bool, ?severity: Symbol | String) -> void
52
+
53
+ # Copy with `path_glob` replaced — plugin config-folding hook for the convention path.
54
+ def with_path_glob: (String glob) -> ProtocolContract
55
+
56
+ # Values are String/bool/nil or the per-param `Hash[String, Integer | String]` rows — kept
57
+ # `untyped` to match the manifest's `to_h` convention.
58
+ def to_h: () -> Hash[String, untyped]
59
+
60
+ def ==: (untyped other) -> bool
61
+
62
+ # `alias eql? ==` — no sig-gen shape for alias rows; unmarked residue.
63
+ def eql?: (untyped other) -> bool
64
+
65
+ def hash: () -> Integer
66
+ end
67
+ end
68
+ end