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
@@ -30,6 +30,7 @@ module Rigor
30
30
  source_path: __FILE__,
31
31
  source_line: __LINE__
32
32
  )
33
+ Ractor.make_shareable(RESULT_DEFINITION)
33
34
 
34
35
  MAYBE_DEFINITION = Inference::HktRegistry.definition_with_body_tree(
35
36
  uri: :"dry_monads::maybe",
@@ -38,6 +39,7 @@ module Rigor
38
39
  source_path: __FILE__,
39
40
  source_line: __LINE__
40
41
  )
42
+ Ractor.make_shareable(MAYBE_DEFINITION)
41
43
 
42
44
  CONSTRUCTOR_METHODS = %i[Success Failure Some None].freeze
43
45
  UNWRAP_METHODS = %i[value! failure value_or].freeze
@@ -23,6 +23,7 @@ module Rigor
23
23
  response_body: -> { Rigor::Type::Combinator.nominal_of("String") },
24
24
  response_headers: -> { Rigor::Type::Combinator.nominal_of("String") }
25
25
  }.freeze
26
+ Ractor.make_shareable(EASY_RETURN_TYPES)
26
27
 
27
28
  dynamic_return receivers: ["Ethon::Easy"], methods: EASY_RETURN_TYPES.keys do |call_node, _scope|
28
29
  builder = EASY_RETURN_TYPES[call_node.name]
@@ -20,7 +20,7 @@ module Rigor
20
20
  ].to_set.freeze
21
21
 
22
22
  # Regex anchor must match end of string \z
23
- NOMINAL_OPAQUE_REGEX = Regexp.new("(_ptr|_handle|Ptr|Handle)\\z")
23
+ NOMINAL_OPAQUE_REGEX = Regexp.new("(_ptr|_handle|Ptr|Handle)\\z").freeze
24
24
 
25
25
  BOOL_TYPE = Rigor::Type::Combinator.union(
26
26
  Rigor::Type::Combinator.constant_of(true),
@@ -0,0 +1,141 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rigor/plugin"
4
+
5
+ module Rigor
6
+ module Plugin
7
+ # rigor-grape — recognises the Grape endpoint-declaration DSL (`class API < Grape::API`) and the
8
+ # grape-entity exposure DSL (`class E < Grape::Entity`) so the calls stop reading `Dynamic[top]`
9
+ # (issue #1099; gitlab's `lib/api` accounted for ~10k opaque implicit-self sends in the
10
+ # 2026-09-19 survey — `expose` ~3.9k, `optional` ~2.2k, `route_setting` ~1.5k, `desc` ~1.4k,
11
+ # `requires` ~1.4k).
12
+ #
13
+ # Grape is more dynamic than the frameworks the ADR-16 substrate was built for:
14
+ #
15
+ # - `Grape::API` subclasses have NO static class methods — every declaration call is forwarded
16
+ # to the base `Grape::API::Instance` class object at runtime (`delegate_missing_to` +
17
+ # `override_all_methods!`, `lib/grape/api.rb`). The bundled sig declares the shared surface
18
+ # once in `Grape::DSL::ClassMethods` and `extend`s it onto both `Grape::API` (reached from
19
+ # source subclasses via `rbs_complete_ancestors`, ADR-43 WD4) and `Grape::API::Instance`
20
+ # (reached inside `namespace` bodies, whose `self` is the Instance class object).
21
+ # - Block `self` bindings differ per macro family — `params` bodies `instance_eval` on a
22
+ # `Grape::Validations::ParamsScope` instance, `namespace`/`route_param`/`version`/`given`/
23
+ # `mounted` bodies on the Instance class object, and verb bodies run as `Grape::Endpoint`
24
+ # instance methods. `block_as_methods` entries carry a named `self_type` ("Foo" /
25
+ # "singleton(Foo)") so each body binds the object Grape actually evaluates it on.
26
+ # - `Grape::Entity`'s `expose` bodies run via `block.call` — `self` stays the Entity class
27
+ # object — so nested `expose` calls need no entry; the `def self.` declarations cover them.
28
+ #
29
+ # ## Deferred (documented in README)
30
+ #
31
+ # - `helpers do ... end` bodies (`class_eval` on an anonymous Module — unnamed self).
32
+ # - Typing `present`/`declared` results against the declared entity/params (runtime shape).
33
+ class Grape < Rigor::Plugin::Base
34
+ # `namespace`-family bodies evaluate as instance methods of the Instance *class object*
35
+ # (`Instance.nest` / `evaluate_as_instance_with_configuration` do `instance_eval(&block)`).
36
+ # `scope` belongs here too: `Grape::DSL::Routing#scope` is `within_namespace { nest(block) }`,
37
+ # so its body `instance_eval`s on the same Instance class object as `namespace`.
38
+ NAMESPACE_METHODS = %i[
39
+ namespace group resource resources segment scope route_param version given mounted
40
+ ].freeze
41
+ # HTTP verb macros are generated over `Grape::HTTP_SUPPORTED_METHODS` and delegate to `route`;
42
+ # their bodies run inside `Grape::Endpoint` instances.
43
+ VERB_METHODS = %i[get put post delete head patch options route].freeze
44
+ # `params` bodies evaluate on a `ParamsScope` instance; the block-carrying scope macros re-enter
45
+ # a child scope the same way.
46
+ PARAMS_SCOPE_METHODS = %i[requires optional given with].freeze
47
+
48
+ manifest(
49
+ id: "grape",
50
+ target_gems: %w[grape grape-entity],
51
+ version: "0.1.0",
52
+ description: "Types the Grape endpoint-declaration DSL (`Grape::API` subclasses: `params`, " \
53
+ "`namespace`, HTTP verb macros, `desc`, `route_setting`, `helpers`) and the " \
54
+ "grape-entity exposure DSL (`Grape::Entity` subclasses: `expose`), including " \
55
+ "the `instance_eval`'d block `self` bindings.",
56
+ signature_paths: ["sig"],
57
+ # ADR-43 WD4 — `Grape::API`/`Grape::Entity` subclasses bridge their class-level DSL calls to
58
+ # the bundled sig's `def self.` declarations. Justified because the bundled sig IS the
59
+ # authority (neither gem ships RBS) and the declared surface is what the DSL exposes.
60
+ rbs_complete_ancestors: %w[
61
+ Grape::API
62
+ Grape::Entity
63
+ ],
64
+ # All five classes have genuinely open runtime surfaces (`override_all_methods!` generates
65
+ # and forwards methods on API subclasses; ParamsScope/Endpoint pick up DSL modules) — calls
66
+ # we don't declare must stay opaque, not diagnosed.
67
+ open_receivers: %w[
68
+ Grape::API
69
+ Grape::API::Instance
70
+ Grape::Entity
71
+ Grape::Validations::ParamsScope
72
+ Grape::Endpoint
73
+ ],
74
+ block_as_methods: [
75
+ # Class-body context: `class API < Grape::API; namespace :x do ... end`.
76
+ Rigor::Plugin::Macro::BlockAsMethod.new(
77
+ receiver_constraint: "Grape::API",
78
+ method_names: NAMESPACE_METHODS,
79
+ self_type: "singleton(Grape::API::Instance)"
80
+ ),
81
+ # Inside an already-narrowed namespace body (self is the Instance class object), nested
82
+ # `namespace`/`version`/`given` calls re-enter the same context.
83
+ Rigor::Plugin::Macro::BlockAsMethod.new(
84
+ receiver_constraint: "Grape::API::Instance",
85
+ method_names: NAMESPACE_METHODS,
86
+ self_type: "singleton(Grape::API::Instance)"
87
+ ),
88
+ # `params do ... end` — body `instance_eval`s on a `ParamsScope` instance.
89
+ Rigor::Plugin::Macro::BlockAsMethod.new(
90
+ receiver_constraint: "Grape::API",
91
+ method_names: %i[params],
92
+ self_type: "Grape::Validations::ParamsScope"
93
+ ),
94
+ Rigor::Plugin::Macro::BlockAsMethod.new(
95
+ receiver_constraint: "Grape::API::Instance",
96
+ method_names: %i[params],
97
+ self_type: "Grape::Validations::ParamsScope"
98
+ ),
99
+ # `requires :x, type: Hash do ... end` inside a params body re-enters a child ParamsScope —
100
+ # the receiver is already the `Nominal[ParamsScope]` `self` of the enclosing body, which is
101
+ # what named-instance `self_type` entries additionally match.
102
+ Rigor::Plugin::Macro::BlockAsMethod.new(
103
+ receiver_constraint: "Grape::Validations::ParamsScope",
104
+ method_names: PARAMS_SCOPE_METHODS,
105
+ self_type: "Grape::Validations::ParamsScope"
106
+ ),
107
+ # `desc 'x' do ... end` — the config block `instance_exec`s on a generated
108
+ # `SettingsContainer` subclass (`StrictHashConfiguration.config_class(*Desc::
109
+ # ROUTE_ATTRIBUTES)` in dsl/desc.rb): `detail`, `success`, `failure`, `tags`, `entity`,
110
+ # `hidden`, `is_array`, `consumes`, `headers`, … each take one value and return it.
111
+ # Modelled as the `Grape::DSL::Desc::ConfigContext` sig carrier — a closed surface, so a
112
+ # misspelt or invented setter still reads `call.undefined-method`, matching the runtime
113
+ # NoMethodError.
114
+ Rigor::Plugin::Macro::BlockAsMethod.new(
115
+ receiver_constraint: "Grape::API",
116
+ method_names: %i[desc],
117
+ self_type: "Grape::DSL::Desc::ConfigContext"
118
+ ),
119
+ Rigor::Plugin::Macro::BlockAsMethod.new(
120
+ receiver_constraint: "Grape::API::Instance",
121
+ method_names: %i[desc],
122
+ self_type: "Grape::DSL::Desc::ConfigContext"
123
+ ),
124
+ # Verb bodies run inside `Grape::Endpoint` instances.
125
+ Rigor::Plugin::Macro::BlockAsMethod.new(
126
+ receiver_constraint: "Grape::API",
127
+ method_names: VERB_METHODS,
128
+ self_type: "Grape::Endpoint"
129
+ ),
130
+ Rigor::Plugin::Macro::BlockAsMethod.new(
131
+ receiver_constraint: "Grape::API::Instance",
132
+ method_names: VERB_METHODS,
133
+ self_type: "Grape::Endpoint"
134
+ )
135
+ ]
136
+ )
137
+ end
138
+
139
+ Rigor::Plugin.register(Grape)
140
+ end
141
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Gem entry point. Required by Rigor's plugin loader when `.rigor.yml` lists `rigor-grape` under
4
+ # `plugins:`. The loader expects this `require` to side-effect a call to `Rigor::Plugin.register`,
5
+ # which the body of `lib/rigor/plugin/grape.rb` performs at load time.
6
+ require_relative "rigor/plugin/grape"
@@ -0,0 +1,263 @@
1
+ # Bundled RBS for the Grape / grape-entity declaration DSL (issue #1099).
2
+ #
3
+ # Grape's class-level endpoint DSL is dynamic at runtime: `Grape::API` subclasses forward every
4
+ # declaration call to the base `Grape::API::Instance` class object via `delegate_missing_to` /
5
+ # `override_all_methods!` (`lib/grape/api.rb`), and the Instance class gets the real definitions
6
+ # from the `included do ... end` bodies of `Grape::DSL::{Routing,Validations,Configuration,
7
+ # Helpers,Callbacks,Middleware,RequestResponse}`. Both sides answer the same singleton surface, so
8
+ # the signatures live once in `Grape::DSL::ClassMethods` and are `extend`ed onto both classes.
9
+ #
10
+ # Return carriers follow the runtime implementation (grape 2.4.0, grape-entity 1.0): setup-style
11
+ # declarations return the bookkeeping collection or the stored setting value, so `::Object?` /
12
+ # `::Array[untyped]` is the honest reading — `void` would be dishonest AND is collapsed to
13
+ # `Dynamic[top]` by the engine's void-value-use recovery, which is exactly what this plugin exists
14
+ # to prevent.
15
+ #
16
+ # Provenance (docs/agents/type-authoring.md): `rigor sig-gen` cannot produce this file — the DSL
17
+ # methods it declares have no `def` in the gems' source (they are generated through
18
+ # `override_all_methods!` / `delegate_missing_to` / `StrictHashConfiguration`), so every entry was
19
+ # hand-derived by reading the grape 2.4.x / grape-entity 1.0 source. Members that do not exist at
20
+ # that version's runtime location are deliberately absent — declaring them would let a genuinely
21
+ # failing call resolve silently.
22
+ #
23
+ # Block `self` bindings are NOT modelled here — they come from the manifest's `block_as_methods`
24
+ # entries (`params` bodies on `Grape::Validations::ParamsScope`, `namespace` bodies on the
25
+ # `Grape::API::Instance` class object, verb bodies on `Grape::Endpoint`).
26
+
27
+ module Grape
28
+ module DSL
29
+ # Class-level declaration surface shared by `Grape::API` subclasses and `Grape::API::Instance`.
30
+ module ClassMethods
31
+ # Validations — `params` opens a `Grape::Validations::ParamsScope` and `instance_eval`s the
32
+ # block on it; returns the new scope (dsl/validations.rb).
33
+ def params: () ?{ () -> untyped } -> Grape::Validations::ParamsScope
34
+ def contract: (?untyped) ?{ () -> untyped } -> ::Object?
35
+
36
+ # Routing — the HTTP verbs are generated over `Grape::HTTP_SUPPORTED_METHODS` and delegate to
37
+ # `route` (`def route(methods, paths = ['/'], route_options = {}, &block)`).
38
+ def get: (*untyped, **untyped) ?{ () -> untyped } -> ::Object?
39
+ def put: (*untyped, **untyped) ?{ () -> untyped } -> ::Object?
40
+ def post: (*untyped, **untyped) ?{ () -> untyped } -> ::Object?
41
+ def delete: (*untyped, **untyped) ?{ () -> untyped } -> ::Object?
42
+ def head: (*untyped, **untyped) ?{ () -> untyped } -> ::Object?
43
+ def patch: (*untyped, **untyped) ?{ () -> untyped } -> ::Object?
44
+ def options: (*untyped, **untyped) ?{ () -> untyped } -> ::Object?
45
+ def route: (untyped, ?untyped, ?untyped) ?{ () -> untyped } -> ::Object?
46
+
47
+ # Namespace family — `namespace`/`scope`/`route_param`/`version`/`given`/`mounted`
48
+ # `instance_eval` their block on the Instance class object and return the block's value.
49
+ # `group`/`resource`/`resources`/`segment` are aliases of `namespace`; `scope` routes
50
+ # through `within_namespace { nest(block) }` (dsl/routing.rb).
51
+ def namespace: (*untyped, **untyped) ?{ () -> untyped } -> ::Object?
52
+ def route_param: (untyped, **untyped) ?{ () -> untyped } -> ::Object?
53
+ def group: (*untyped, **untyped) ?{ () -> untyped } -> ::Object?
54
+ def resource: (*untyped, **untyped) ?{ () -> untyped } -> ::Object?
55
+ def resources: (*untyped, **untyped) ?{ () -> untyped } -> ::Object?
56
+ def segment: (*untyped, **untyped) ?{ () -> untyped } -> ::Object?
57
+ def version: (*untyped, **untyped) ?{ () -> untyped } -> ::Object?
58
+ def given: (*untyped, **untyped) ?{ () -> untyped } -> ::Object?
59
+ def mounted: () { () -> untyped } -> ::Object?
60
+ def mount: (untyped, *untyped) -> ::Object?
61
+ def scope: (*untyped, **untyped) ?{ () -> untyped } -> ::Object?
62
+ def prefix: (?untyped) -> ::Object?
63
+
64
+ # Settings / configuration (dsl/settings.rb, dsl/configuration.rb).
65
+ def route_setting: (untyped, ?untyped) -> ::Object?
66
+ def unset_route_setting: (untyped) -> ::Object?
67
+ def global_setting: (untyped, ?untyped) -> ::Object?
68
+ def unset_global_setting: (untyped) -> ::Object?
69
+ # `description` / `entity` / `detail` / `failure` / `success` and friends are NOT API-level
70
+ # methods — they belong to the anonymous `config_context` a `desc` block `instance_exec`s on
71
+ # (`Grape::Util::StrictHashConfiguration`). That surface is deferred (README); declaring the
72
+ # names here would silently resolve calls that fail at runtime.
73
+ def desc: (untyped, ?untyped) ?{ () -> untyped } -> ::Object?
74
+ def content_type: (untyped, untyped) -> ::Object?
75
+ def default_format: (?untyped) -> ::Object?
76
+ def format: (?untyped) -> ::Object?
77
+ def formatter: (untyped, untyped) -> ::Object?
78
+ def parser: (untyped, untyped) -> ::Object?
79
+ def default_error_formatter: (?untyped) -> ::Object?
80
+ def default_error_status: (?untyped) -> ::Object?
81
+ def error_formatter: (untyped, untyped) -> ::Object?
82
+ def cascade: (?untyped) -> ::Object?
83
+ def do_not_route_head!: () -> ::Object?
84
+ def do_not_route_options!: () -> ::Object?
85
+ def do_not_document!: () -> ::Object?
86
+ def http_basic: (*untyped, **untyped) ?{ () -> untyped } -> ::Object?
87
+ def auth: (*untyped, **untyped) ?{ () -> untyped } -> ::Object?
88
+ def http_digest: (*untyped, **untyped) ?{ () -> untyped } -> ::Object?
89
+ def rescue_from: (*untyped, **untyped) ?{ (*untyped) -> untyped } -> ::Object?
90
+ # `represent` forwards to `Entity.represent`, whose result is an entity, an array of
91
+ # entities, or a `{root => inner}` Hash depending on the call — untyped is the honest
92
+ # carrier (a `::Object` return invents `undefined method` findings on every chained call).
93
+ # Runtime arity is `represent(model_class, options)` (dsl/request_response.rb).
94
+ def represent: (untyped, untyped) -> untyped
95
+
96
+ # Helpers / middleware / callbacks.
97
+ def helpers: (*untyped) ?{ () -> untyped } -> ::Object?
98
+ def use: (*untyped, **untyped) ?{ () -> untyped } -> ::Object?
99
+ def middleware: () -> ::Object?
100
+ def insert_before: (*untyped, **untyped) ?{ () -> untyped } -> ::Object?
101
+ def insert_after: (*untyped, **untyped) ?{ () -> untyped } -> ::Object?
102
+ def before: () { () -> untyped } -> ::Object?
103
+ def before_validation: () { () -> untyped } -> ::Object?
104
+ def after_validation: () { () -> untyped } -> ::Object?
105
+ def after: () { () -> untyped } -> ::Object?
106
+ def finally: () { () -> untyped } -> ::Object?
107
+ end
108
+
109
+ module Desc
110
+ # The `instance_exec` target of a `desc 'x' do ... end` config block. At runtime this is an
111
+ # anonymous class built by `StrictHashConfiguration.config_class(*Desc::ROUTE_ATTRIBUTES)`
112
+ # (`dsl/desc.rb` `desc_container`) — a CLOSED surface of one-argument setters that store and
113
+ # return the assigned value (`@settings[name] = new_value`), plus the `success`/`failure`
114
+ # aliases singleton-defined on the context. Names outside `ROUTE_ATTRIBUTES` raise
115
+ # `NoMethodError` at runtime, so this receiver stays out of `open_receivers`: an undeclared
116
+ # call inside a `desc` block genuinely fails.
117
+ class ConfigContext
118
+ def body_name: (untyped) -> ::Object?
119
+ def consumes: (untyped) -> ::Object?
120
+ def default: (untyped) -> ::Object?
121
+ def deprecated: (untyped) -> ::Object?
122
+ def description: (untyped) -> ::Object?
123
+ def detail: (untyped) -> ::Object?
124
+ def entity: (untyped) -> ::Object?
125
+ def headers: (untyped) -> ::Object?
126
+ def hidden: (untyped) -> ::Object?
127
+ def http_codes: (untyped) -> ::Object?
128
+ def is_array: (untyped) -> ::Object?
129
+ def named: (untyped) -> ::Object?
130
+ def nickname: (untyped) -> ::Object?
131
+ def params: (untyped) -> ::Object?
132
+ def produces: (untyped) -> ::Object?
133
+ def security: (untyped) -> ::Object?
134
+ def summary: (untyped) -> ::Object?
135
+ def tags: (untyped) -> ::Object?
136
+ def success: (*untyped) -> ::Object?
137
+ def failure: (*untyped) -> ::Object?
138
+ def configuration: () -> untyped
139
+ def to_hash: () -> ::Hash[untyped, untyped]
140
+ end
141
+ end
142
+ end
143
+
144
+ class API
145
+ extend DSL::ClassMethods
146
+
147
+ # The class object a `Grape::API` subclass's declaration calls are forwarded to. `namespace`
148
+ # bodies `instance_eval` on this class object, so the same `extend`ed surface covers calls made
149
+ # inside them.
150
+ class Instance
151
+ extend DSL::ClassMethods
152
+ end
153
+ end
154
+
155
+ module Validations
156
+ # The receiver `params`/`requires`/`optional`/`given`/`with` blocks `instance_eval` on. Its
157
+ # DSL lives in `Grape::DSL::Parameters`; the declarations here cover the block-relevant and
158
+ # commonly-called subset.
159
+ class ParamsScope
160
+ def requires: (*untyped, **untyped) ?{ () -> untyped } -> ::Object?
161
+ def optional: (*untyped, **untyped) ?{ () -> untyped } -> ::Object?
162
+ def given: (*untyped, **untyped) ?{ () -> untyped } -> ::Object?
163
+ def with: (*untyped, **untyped) ?{ () -> untyped } -> ::Object?
164
+ def use: (*untyped) -> ::Object?
165
+ def mutually_exclusive: (*untyped) -> ::Object?
166
+ def exactly_one_of: (*untyped) -> ::Object?
167
+ def at_least_one_of: (*untyped) -> ::Object?
168
+ def all_or_none_of: (*untyped) -> ::Object?
169
+ end
170
+ end
171
+
172
+ # Runtime route context — verb bodies execute as `Grape::Endpoint` instance methods
173
+ # (`Grape::Endpoint#run` evaluates the stored block inside the endpoint instance). The methods
174
+ # here are `Grape::DSL::InsideRoute`, `Grape::DSL::Headers`, `Grape::DSL::Settings`, and the
175
+ # `def_delegators :request` surface (`params`/`headers`/`cookies`).
176
+ class Endpoint
177
+ def params: () -> ::Hash[untyped, untyped]
178
+ def headers: () -> ::Hash[untyped, untyped]
179
+ # `Endpoint#cookies` delegates to `Grape::Request#cookies`, which builds a `Grape::Cookies`
180
+ # wrapper — not a Hash (`lib/grape/cookies.rb`, `lib/grape/request.rb`).
181
+ def cookies: () -> Grape::Cookies
182
+ def env: () -> ::Hash[untyped, untyped]
183
+ # `request` is a `Grape::Request` (Rack::Request subclass) at runtime — untyped rather than
184
+ # `::Object` so `request.params`/`request.GET` chains don't read as undefined-method findings.
185
+ def request: () -> untyped
186
+ def declared: (*untyped, **untyped) -> ::Hash[untyped, untyped]
187
+ def version: () -> ::Object?
188
+ def error!: (*untyped, **untyped) -> bot
189
+ def redirect: (untyped url, ?permanent: untyped, ?body: untyped) -> ::Object?
190
+ def status: (?untyped) -> ::Object?
191
+ def content_type: (?untyped) -> ::Object?
192
+ def body: (?untyped) -> ::Object?
193
+ # `present` returns the representation (entity, Hash, or the bare object) — untyped.
194
+ def present: (*untyped, **untyped) -> untyped
195
+ # `route` is the `Grape::Router::Route` for the current endpoint — untyped.
196
+ def route: () -> untyped
197
+ def header: (?untyped, ?untyped) -> ::Object?
198
+ def route_setting: (untyped, ?untyped) -> ::Object?
199
+ def stream: (?untyped) -> ::Object?
200
+ def sendfile: (?untyped) -> ::Object?
201
+ # `error_response` lives on `Grape::Middleware::Error`, not on the endpoint — not declared here.
202
+ end
203
+
204
+ # The Rack-cookie wrapper `Grape::Request#cookies` returns (`def_delegators :cookies` for `[]`
205
+ # and `each`, plus its own `[]=` / `delete` / `response_cookies`). Not a Hash.
206
+ class Cookies
207
+ def []: (untyped) -> untyped
208
+ def []=: (untyped, untyped) -> untyped
209
+ def each: (*untyped) ?{ (*untyped) -> untyped } -> untyped
210
+ def response_cookies: () { (untyped, untyped) -> untyped } -> untyped
211
+ def delete: (untyped, **untyped) -> untyped
212
+ end
213
+
214
+ # grape-entity's declaration target (`class Foo < Grape::Entity`). `expose` bodies run via
215
+ # `block.call` — `self` stays the Entity subclass's class object — so nested `expose` calls
216
+ # resolve through the same singleton surface without a `block_as_methods` entry.
217
+ class Entity
218
+ def self.expose: (*untyped, **untyped) ?{ () -> untyped } -> ::Array[untyped]
219
+ def self.unexpose: (*untyped) -> ::Object?
220
+ def self.unexpose_all: () -> ::Object?
221
+ def self.with_options: (untyped) { () -> untyped } -> ::Object?
222
+ def self.documentation: () -> ::Hash[untyped, untyped]
223
+ # Returns `formatters[name.to_sym] = block` — the registered Proc.
224
+ def self.format_with: (untyped) { (untyped) -> untyped } -> ::Proc
225
+ def self.root: (untyped, ?untyped) -> ::Object?
226
+ def self.root_element: (untyped) -> ::Object?
227
+ # Result is an Entity instance, an Array of them, or a `{root => inner}` Hash
228
+ # (`lib/grape_entity/entity.rb` `self.represent`) — untyped, not `::Object`, so chained
229
+ # `serializable_hash` / `map` / exposed-attribute reads stay quiet.
230
+ def self.represent: (*untyped, **untyped) -> untyped
231
+ def self.present_collection: (?untyped, ?untyped) -> ::Object?
232
+ # Runtime returns `Exposure::NestingExposure::NestedExposures` — an `Enumerable` wrapper with
233
+ # `find_by` / `select_by` / `delete_by` that Array does not have.
234
+ def self.root_exposures: () -> Exposure::NestingExposure::NestedExposures
235
+
236
+ # The instance-side output surface — `serializable_hash` is the primary representation
237
+ # output (`nil` when the wrapped object is nil); `as_json`/`to_json` delegate to it.
238
+ def serializable_hash: (?untyped) -> ::Hash[untyped, untyped]?
239
+ def as_json: (*untyped, **untyped) -> untyped
240
+
241
+ module Exposure
242
+ class NestingExposure
243
+ # `Enumerable` wrapper over the exposure list (grape-entity `nested_exposures.rb`):
244
+ # `each`/`to_ary`/`to_a`/`[]`/`size`/`empty?`/`==` delegate to the inner Array, and
245
+ # `find_by`/`select_by`/`delete_by`/`<<`/`clear` are its own API.
246
+ class NestedExposures
247
+ include Enumerable[untyped]
248
+ def find_by: (untyped) -> untyped
249
+ def select_by: (untyped) -> untyped
250
+ def <<: (untyped) -> untyped
251
+ def delete_by: (*untyped) -> untyped
252
+ def clear: () -> untyped
253
+ def to_ary: () -> ::Array[untyped]
254
+ def to_a: () -> ::Array[untyped]
255
+ def []: (*untyped) -> untyped
256
+ def ==: (untyped) -> bool
257
+ def size: () -> ::Integer
258
+ def empty?: () -> bool
259
+ end
260
+ end
261
+ end
262
+ end
263
+ end
@@ -40,6 +40,21 @@ module Rigor
40
40
  # required: ...` declarations.
41
41
  # - No user-facing diagnostics yet.
42
42
  #
43
+ # ## Shipped DSL signature (`sig/graphql.rbs`)
44
+ #
45
+ # Since graphql-ruby ships no RBS, the manifest's `signature_paths:` contributes the class-level
46
+ # DSL surface — `field`/`argument`/`value`/`implements`/`description`/`graphql_name` and friends —
47
+ # following graphql-ruby's real `Member`-rooted ancestry so subclass bodies stop reading every
48
+ # DSL call as `Dynamic[top]`. Return types are the real carriers (`field` → `Schema::Field`,
49
+ # `Enum.value` → `Schema::EnumValue`, setter/getter macros → their configured value) rather than
50
+ # `void`, which the engine recovers as `top`. Scope and deferrals are documented at the top of
51
+ # the sig file.
52
+ #
53
+ # The declared classes stay in `open_receivers:` because graphql-ruby's real surface is open:
54
+ # schema plugins (`use`-able extensions) and user base classes add class-level DSL methods this
55
+ # signature does not enumerate, so `call.undefined-method` must not read these classes as
56
+ # closed.
57
+ #
43
58
  # ## Deferred (demand-driven)
44
59
  #
45
60
  # - **`resolver:` / `mutation:` reroute** recognition.
@@ -51,11 +66,66 @@ module Rigor
51
66
  manifest(
52
67
  id: "graphql",
53
68
  target_gems: ["graphql"],
54
- version: "0.1.0",
69
+ # 0.2.0, 2026-09-20 (#1100) — `signature_paths:` contributes the graphql-ruby class-level DSL
70
+ # surface (`field`/`argument`/`value`/…), typed with the real carriers (`Field`/`Argument`/
71
+ # `EnumValue`/…) so DSL calls stop reading `Dynamic[top]` inside recognised subclasses.
72
+ version: "0.2.0",
55
73
  description: "Recognises `class T < GraphQL::Schema::{Object,Enum,InputObject,Mutation}` " \
56
74
  "subclasses; publishes the per-type field-type table, the per-enum value " \
57
75
  "list, the per-input-object argument table, and the per-mutation arguments+fields " \
58
- "table.",
76
+ "table; ships the graphql-ruby class-level DSL signature surface.",
77
+ signature_paths: ["sig"],
78
+ # ADR-43 WD4 — the classes the bundled sig covers completely enough that a Ruby-source subclass
79
+ # (`class PostType < GraphQL::Schema::Object`) may bridge inherited calls to the RBS ancestor.
80
+ # Listing one turns on `call.undefined-method`/arity checks for inherited DSL calls on every
81
+ # subclass — justified here because the sig IS the authority (graphql-ruby ships none).
82
+ rbs_complete_ancestors: %w[
83
+ GraphQL::Schema
84
+ GraphQL::Schema::Member
85
+ GraphQL::Schema::Object
86
+ GraphQL::Schema::Resolver
87
+ GraphQL::Schema::Mutation
88
+ GraphQL::Schema::RelayClassicMutation
89
+ GraphQL::Schema::Subscription
90
+ GraphQL::Schema::InputObject
91
+ GraphQL::Schema::Enum
92
+ GraphQL::Schema::EnumValue
93
+ GraphQL::Schema::Union
94
+ GraphQL::Schema::Scalar
95
+ GraphQL::Schema::Directive
96
+ GraphQL::Schema::Field
97
+ GraphQL::Schema::Argument
98
+ GraphQL::Dataloader::Source
99
+ GraphQL::Types::Relay::BaseConnection
100
+ GraphQL::Types::Relay::BaseEdge
101
+ GraphQL::Types::Relay::PageInfo
102
+ GraphQL::Types::Relay::BaseField
103
+ ],
104
+ open_receivers: %w[
105
+ GraphQL::Schema
106
+ GraphQL::Schema::Member
107
+ GraphQL::Schema::Object
108
+ GraphQL::Schema::Resolver
109
+ GraphQL::Schema::Mutation
110
+ GraphQL::Schema::RelayClassicMutation
111
+ GraphQL::Schema::Subscription
112
+ GraphQL::Schema::InputObject
113
+ GraphQL::Schema::Enum
114
+ GraphQL::Schema::EnumValue
115
+ GraphQL::Schema::Union
116
+ GraphQL::Schema::Scalar
117
+ GraphQL::Schema::Directive
118
+ GraphQL::Schema::Field
119
+ GraphQL::Schema::Argument
120
+ GraphQL::Schema::Interface
121
+ GraphQL::Query
122
+ GraphQL::Query::Context
123
+ GraphQL::Dataloader
124
+ GraphQL::Dataloader::Source
125
+ GraphQL::Types::Relay::BaseConnection
126
+ GraphQL::Types::Relay::BaseEdge
127
+ GraphQL::Types::Relay::BaseField
128
+ ],
59
129
  produces: %i[graphql_type_table graphql_enum_table graphql_input_object_table graphql_mutation_table]
60
130
  )
61
131