feat: add RBS type signatures with Steep type checking#251
Conversation
Add RBS/Steep type checking tooling: - Add steep gem to development dependencies - Create Steepfile with lenient diagnostics for lib/ - Create rbs_collection.yaml for stdlib type dependencies - Add Steep::RakeTask to Rakefile - Add .gem_rbs_collection/ to .gitignore Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Jose Colella <jose.colella@gusto.com>
Add 31 RBS signature files under sig/ mirroring the lib/ structure: - Provider duck-type contract via _Provider interface - Hook lifecycle contract via _Hook interface - TransactionContextPropagator interface - All 12 dynamically generated Client methods declared explicitly - SDK module method_missing delegates declared as explicit self.* methods - Struct types (ResolutionDetails, EvaluationDetails, ClientMetadata, etc.) - Constants modules (ErrorCode, Reason, ProviderEvent, ProviderState) - Core classes (Configuration, API, EventDispatcher, ProviderStateRegistry) - Hints declared as plain class (DelegateClass unsupported in RBS) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Jose Colella <jose.colella@gusto.com>
- Add steep CI job to GitHub Actions workflow - Gate status check on steep job passing - Document type check command and sig/ convention in CLAUDE.md Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Jose Colella <jose.colella@gusto.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #251 +/- ##
=======================================
Coverage 99.50% 99.50%
=======================================
Files 31 31
Lines 808 808
=======================================
Hits 804 804
Misses 4 4 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request significantly enhances the OpenFeature Ruby SDK by integrating static type checking using RBS and Steep. This initiative aims to improve code quality, maintainability, and developer experience by catching type-related errors early and providing better IDE support. The changes involve adding comprehensive type signatures for the entire SDK, configuring the Steep type checker, and incorporating type validation into the continuous integration pipeline. Highlights
Ignored Files
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here. Footnotes
|
Set explicit top-level permissions with minimal `contents: read` to satisfy security scanning requirements. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Jose Colella <jose.colella@gusto.com>
There was a problem hiding this comment.
Code Review
This pull request introduces a comprehensive set of RBS type signatures for the entire lib directory and integrates Steep for static type checking. This is a significant enhancement to the project's maintainability and code quality. The changes are thorough, covering public and private APIs, constants, and even dynamically generated methods. The configuration for Steep and management of RBS collections appears correct. I have one suggestion to further improve the type safety of event handlers. Overall, this is an excellent and well-executed contribution.
| end | ||
|
|
||
| interface _ToProc | ||
| def call: (untyped) -> untyped |
There was a problem hiding this comment.
The _ToProc interface can be made more specific. Event handlers are always called with a Hash[Symbol, untyped] as an argument. Changing the signature to reflect this will improve type safety. Additionally, since the return value of the handler is not used, void is a more idiomatic return type than untyped.
def call: (Hash[Symbol, untyped]) -> void
There was a problem hiding this comment.
Good catch — narrowed to (Hash[Symbol, untyped]) -> void in 0fac9d9.
🤖 Jose's AI agent
Narrow the handler interface signature from `(untyped) -> untyped` to `(Hash[Symbol, untyped]) -> void` since event handlers always receive event details hashes and their return values are unused. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Jose Colella <jose.colella@gusto.com>
There was a problem hiding this comment.
Pull request overview
Adds Steep-based type checking to the OpenFeature Ruby SDK by introducing Steep configuration, RBS signatures that mirror the lib/ API, and CI automation to enforce type checks.
Changes:
- Introduce Steep config (
Steepfile) and RBS collection configuration (rbs_collection.yaml/ lock). - Add initial RBS signatures under
sig/for core SDK surface area (API, client, configuration, hooks, providers, telemetry, etc.). - Wire Steep into development workflow (Gemfile + lock, Rakefile task, CI job, docs, gitignore).
Reviewed changes
Copilot reviewed 38 out of 40 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| Steepfile | Defines Steep target, signature/check paths, diagnostic settings |
| sig/open_feature/sdk/version.rbs | Types OpenFeature::SDK::VERSION |
| sig/open_feature/sdk/transaction_context_propagator.rbs | Types transaction context propagator interface/module |
| sig/open_feature/sdk/tracking_event_details.rbs | Types TrackingEventDetails |
| sig/open_feature/sdk/thread_local_transaction_context_propagator.rbs | Types thread-local propagator implementation |
| sig/open_feature/sdk/telemetry.rbs | Types telemetry constants and event creation API |
| sig/open_feature/sdk/provider/resolution_details.rbs | Types provider resolution details struct + metadata |
| sig/open_feature/sdk/provider/reason.rbs | Types provider reason constants |
| sig/open_feature/sdk/provider/provider_metadata.rbs | Types provider metadata struct |
| sig/open_feature/sdk/provider/no_op_provider.rbs | Types NoOp provider implementation |
| sig/open_feature/sdk/provider/in_memory_provider.rbs | Types in-memory provider implementation |
| sig/open_feature/sdk/provider/event_emitter.rbs | Types provider event emitter mixin |
| sig/open_feature/sdk/provider/error_code.rbs | Types provider error code constants |
| sig/open_feature/sdk/provider.rbs | Types provider interfaces |
| sig/open_feature/sdk/provider_state.rbs | Types provider state constants |
| sig/open_feature/sdk/provider_state_registry.rbs | Types provider state registry |
| sig/open_feature/sdk/provider_initialization_error.rbs | Types initialization error class |
| sig/open_feature/sdk/provider_event.rbs | Types provider event constants |
| sig/open_feature/sdk/hooks/logging_hook.rbs | Types logging hook |
| sig/open_feature/sdk/hooks/hook.rbs | Types hook interface/module |
| sig/open_feature/sdk/hooks/hook_executor.rbs | Types hook executor |
| sig/open_feature/sdk/hooks/hook_context.rbs | Types hook context |
| sig/open_feature/sdk/hooks/hints.rbs | Types hook hints wrapper |
| sig/open_feature/sdk/event_dispatcher.rbs | Types event dispatcher + handler callable interface |
| sig/open_feature/sdk/evaluation_details.rbs | Types evaluation details struct/delegators |
| sig/open_feature/sdk/evaluation_context.rbs | Types evaluation context |
| sig/open_feature/sdk/evaluation_context_builder.rbs | Types evaluation context builder |
| sig/open_feature/sdk/configuration.rbs | Types global configuration object |
| sig/open_feature/sdk/client.rbs | Types client public API + private helpers |
| sig/open_feature/sdk/client_metadata.rbs | Types client metadata struct |
| sig/open_feature/sdk/api.rbs | Types API singleton surface |
| sig/open_feature/sdk.rbs | Types module-level delegation surface |
| rbs_collection.yaml | Configures external RBS sources and stdlib gems |
| rbs_collection.lock.yaml | Locks resolved RBS dependencies and versions |
| Rakefile | Adds optional Steep rake task |
| Gemfile.lock | Adds Steep and dependencies to lockfile |
| Gemfile | Adds steep to development/test dependencies |
| CLAUDE.md | Documents steep install/type-check commands and sig/ conventions |
| .gitignore | Ignores .gem_rbs_collection/ cache |
| .github/workflows/main.yml | Adds Steep type-check job and includes it in CI status |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
|
|
||
| def initialize: () -> void | ||
|
|
||
| def add_hooks: (*Array[untyped] new_hooks) -> void |
|
|
||
| def initialize: (provider: untyped, ?domain: String?, ?evaluation_context: EvaluationContext?) -> void | ||
|
|
||
| def add_hooks: (*Array[untyped] new_hooks) -> void |
| def set_provider: (untyped provider, ?domain: String?) -> void | ||
| def set_provider_and_wait: (untyped provider, ?domain: String?) -> void | ||
| def hooks: () -> Array[untyped] | ||
| def add_hooks: (*Array[untyped] new_hooks) -> void |
|
|
||
| def run_short_circuit: (ordered_hooks: Array[untyped], hook_context: HookContext, hints: Hints, evaluation_details: EvaluationDetails) -> void | ||
|
|
||
| def execute: (ordered_hooks: Array[untyped], hook_context: HookContext, hints: Hints) { (HookContext) -> EvaluationDetails } -> EvaluationDetails? |
|
|
||
| private | ||
|
|
||
| def fetch_details: (type: Symbol, flag_key: String, default_value: untyped, ?evaluation_context: EvaluationContext?, ?invocation_hooks: Array[untyped], ?hook_hints: Hooks::Hints?) -> EvaluationDetails? |
|
|
||
| def configuration: () -> Configuration | ||
|
|
||
| def configure: () { (Configuration) -> void } -> void |
| module OpenFeature | ||
| module SDK | ||
| # Delegated to API.instance via method_missing | ||
| def self.configure: () { (Configuration) -> void } -> void |
Summary
lib/, providing static type safety and IDE autocompletion for gem consumersbundle exec steep checkpassingsig/convention in CLAUDE.md: anylib/change must include corresponding RBS updatesDetails
31 RBS files in
sig/mirrorlib/structure, covering:_Providerinterface formalizing the provider duck-type contract_Hookinterface for the hook lifecycle_TransactionContextPropagatorinterfaceClientmethods declared explicitlySDKmodulemethod_missingdelegates declared asself.*methodsKey design decisions:
untypedfor flag values — genuinely polymorphic; precise types onfetch_*_valuereturn typesDelegateClasssupport; commonly used Hash methods declared explicitlysig/shipped with gem — auto-included via existinggit ls-filesgemspec patternTest plan
bundle exec rbs -I sig validate— cleanbundle exec steep check— no type errorsbundle exec rspec— 420 examples, 0 failures (99.5% coverage)bundle exec standardrb— no offenses🤖 Jose's AI agent