openfeature-sdk 0.6.4 → 0.6.6

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 (67) hide show
  1. checksums.yaml +4 -4
  2. data/.release-please-manifest.json +1 -1
  3. data/.ruby-version +1 -1
  4. data/.tool-versions +1 -1
  5. data/.yardopts +5 -0
  6. data/CHANGELOG.md +20 -0
  7. data/CLAUDE.md +4 -1
  8. data/CONTRIBUTING.md +15 -1
  9. data/Gemfile +17 -2
  10. data/Gemfile.lock +98 -67
  11. data/README.md +24 -8
  12. data/Rakefile +14 -0
  13. data/SECURITY.md +10 -0
  14. data/Steepfile +7 -0
  15. data/examples/basic_usage.rb +22 -0
  16. data/examples/custom_provider.rb +56 -0
  17. data/examples/rails_integration.rb +60 -0
  18. data/lib/open_feature/sdk/api.rb +1 -0
  19. data/lib/open_feature/sdk/client.rb +2 -3
  20. data/lib/open_feature/sdk/configuration.rb +26 -13
  21. data/lib/open_feature/sdk/evaluation_error.rb +28 -0
  22. data/lib/open_feature/sdk/hooks/hook_executor.rb +5 -5
  23. data/lib/open_feature/sdk/hooks/logging_hook.rb +1 -2
  24. data/lib/open_feature/sdk/provider/in_memory_provider.rb +24 -0
  25. data/lib/open_feature/sdk/provider_event.rb +5 -1
  26. data/lib/open_feature/sdk/provider_state_registry.rb +2 -2
  27. data/lib/open_feature/sdk/version.rb +1 -1
  28. data/openfeature-sdk.gemspec +34 -0
  29. data/rbs_collection.lock.yaml +292 -0
  30. data/rbs_collection.yaml +14 -0
  31. data/renovate.json +1 -1
  32. data/sig/open_feature/sdk/api.rbs +35 -0
  33. data/sig/open_feature/sdk/client.rbs +49 -0
  34. data/sig/open_feature/sdk/client_metadata.rbs +11 -0
  35. data/sig/open_feature/sdk/configuration.rbs +44 -0
  36. data/sig/open_feature/sdk/evaluation_context.rbs +19 -0
  37. data/sig/open_feature/sdk/evaluation_context_builder.rbs +7 -0
  38. data/sig/open_feature/sdk/evaluation_details.rbs +19 -0
  39. data/sig/open_feature/sdk/evaluation_error.rbs +11 -0
  40. data/sig/open_feature/sdk/event_dispatcher.rbs +24 -0
  41. data/sig/open_feature/sdk/hooks/hints.rbs +30 -0
  42. data/sig/open_feature/sdk/hooks/hook.rbs +19 -0
  43. data/sig/open_feature/sdk/hooks/hook_context.rbs +18 -0
  44. data/sig/open_feature/sdk/hooks/hook_executor.rbs +20 -0
  45. data/sig/open_feature/sdk/hooks/logging_hook.rbs +25 -0
  46. data/sig/open_feature/sdk/provider/error_code.rbs +16 -0
  47. data/sig/open_feature/sdk/provider/event_emitter.rbs +16 -0
  48. data/sig/open_feature/sdk/provider/in_memory_provider.rbs +46 -0
  49. data/sig/open_feature/sdk/provider/no_op_provider.rbs +25 -0
  50. data/sig/open_feature/sdk/provider/provider_metadata.rbs +11 -0
  51. data/sig/open_feature/sdk/provider/reason.rbs +17 -0
  52. data/sig/open_feature/sdk/provider/resolution_details.rbs +19 -0
  53. data/sig/open_feature/sdk/provider.rbs +24 -0
  54. data/sig/open_feature/sdk/provider_event.rbs +14 -0
  55. data/sig/open_feature/sdk/provider_initialization_error.rbs +11 -0
  56. data/sig/open_feature/sdk/provider_state.rbs +13 -0
  57. data/sig/open_feature/sdk/provider_state_registry.rbs +22 -0
  58. data/sig/open_feature/sdk/telemetry.rbs +29 -0
  59. data/sig/open_feature/sdk/thread_local_transaction_context_propagator.rbs +12 -0
  60. data/sig/open_feature/sdk/tracking_event_details.rbs +10 -0
  61. data/sig/open_feature/sdk/transaction_context_propagator.rbs +11 -0
  62. data/sig/open_feature/sdk/version.rbs +5 -0
  63. data/sig/open_feature/sdk.rbs +22 -0
  64. metadata +54 -140
  65. data/.simplecov +0 -12
  66. data/docs/plans/2026-03-07-telemetry-utility-design.md +0 -98
  67. data/docs/plans/2026-03-07-telemetry-utility-plan.md +0 -578
@@ -0,0 +1,10 @@
1
+ module OpenFeature
2
+ module SDK
3
+ class TrackingEventDetails
4
+ attr_reader value: Numeric?
5
+ attr_reader fields: Hash[String, untyped]
6
+
7
+ def initialize: (?value: Numeric?, **untyped fields) -> void
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,11 @@
1
+ module OpenFeature
2
+ module SDK
3
+ interface _TransactionContextPropagator
4
+ def set_transaction_context: (EvaluationContext evaluation_context) -> void
5
+ def get_transaction_context: () -> EvaluationContext?
6
+ end
7
+
8
+ module TransactionContextPropagator : _TransactionContextPropagator
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,5 @@
1
+ module OpenFeature
2
+ module SDK
3
+ VERSION: String
4
+ end
5
+ end
@@ -0,0 +1,22 @@
1
+ module OpenFeature
2
+ module SDK
3
+ # Delegated to API.instance via method_missing
4
+ def self.configure: () { (Configuration) -> void } -> void
5
+ def self.build_client: (?domain: String?, ?evaluation_context: EvaluationContext?) -> Client
6
+ def self.configuration: () -> Configuration
7
+ def self.provider: (?domain: String?) -> untyped?
8
+ def self.set_provider: (untyped provider, ?domain: String?) -> void
9
+ def self.set_provider_and_wait: (untyped provider, ?domain: String?) -> void
10
+ def self.hooks: () -> Array[untyped]
11
+ def self.add_hooks: (*Array[untyped] new_hooks) -> void
12
+ def self.evaluation_context: () -> EvaluationContext?
13
+ def self.add_handler: (String event_type, _ToProc handler) -> void
14
+ def self.remove_handler: (String event_type, _ToProc handler) -> void
15
+ def self.logger: () -> untyped?
16
+ def self.logger=: (untyped? new_logger) -> void
17
+ def self.set_transaction_context_propagator: (_TransactionContextPropagator propagator) -> void
18
+ def self.set_transaction_context: (EvaluationContext evaluation_context) -> void
19
+ def self.shutdown: () -> void
20
+ def self.provider_metadata: (?domain: String?) -> Provider::ProviderMetadata?
21
+ end
22
+ end
metadata CHANGED
@@ -1,142 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: openfeature-sdk
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.4
4
+ version: 0.6.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - OpenFeature Authors
8
8
  bindir: exe
9
9
  cert_chain: []
10
10
  date: 1980-01-02 00:00:00.000000000 Z
11
- dependencies:
12
- - !ruby/object:Gem::Dependency
13
- name: debug
14
- requirement: !ruby/object:Gem::Requirement
15
- requirements:
16
- - - ">="
17
- - !ruby/object:Gem::Version
18
- version: '0'
19
- type: :development
20
- prerelease: false
21
- version_requirements: !ruby/object:Gem::Requirement
22
- requirements:
23
- - - ">="
24
- - !ruby/object:Gem::Version
25
- version: '0'
26
- - !ruby/object:Gem::Dependency
27
- name: markly
28
- requirement: !ruby/object:Gem::Requirement
29
- requirements:
30
- - - ">="
31
- - !ruby/object:Gem::Version
32
- version: '0'
33
- type: :development
34
- prerelease: false
35
- version_requirements: !ruby/object:Gem::Requirement
36
- requirements:
37
- - - ">="
38
- - !ruby/object:Gem::Version
39
- version: '0'
40
- - !ruby/object:Gem::Dependency
41
- name: rake
42
- requirement: !ruby/object:Gem::Requirement
43
- requirements:
44
- - - "~>"
45
- - !ruby/object:Gem::Version
46
- version: '13.0'
47
- type: :development
48
- prerelease: false
49
- version_requirements: !ruby/object:Gem::Requirement
50
- requirements:
51
- - - "~>"
52
- - !ruby/object:Gem::Version
53
- version: '13.0'
54
- - !ruby/object:Gem::Dependency
55
- name: rspec
56
- requirement: !ruby/object:Gem::Requirement
57
- requirements:
58
- - - "~>"
59
- - !ruby/object:Gem::Version
60
- version: 3.12.0
61
- type: :development
62
- prerelease: false
63
- version_requirements: !ruby/object:Gem::Requirement
64
- requirements:
65
- - - "~>"
66
- - !ruby/object:Gem::Version
67
- version: 3.12.0
68
- - !ruby/object:Gem::Dependency
69
- name: standard
70
- requirement: !ruby/object:Gem::Requirement
71
- requirements:
72
- - - ">="
73
- - !ruby/object:Gem::Version
74
- version: '0'
75
- type: :development
76
- prerelease: false
77
- version_requirements: !ruby/object:Gem::Requirement
78
- requirements:
79
- - - ">="
80
- - !ruby/object:Gem::Version
81
- version: '0'
82
- - !ruby/object:Gem::Dependency
83
- name: standard-performance
84
- requirement: !ruby/object:Gem::Requirement
85
- requirements:
86
- - - ">="
87
- - !ruby/object:Gem::Version
88
- version: '0'
89
- type: :development
90
- prerelease: false
91
- version_requirements: !ruby/object:Gem::Requirement
92
- requirements:
93
- - - ">="
94
- - !ruby/object:Gem::Version
95
- version: '0'
96
- - !ruby/object:Gem::Dependency
97
- name: simplecov
98
- requirement: !ruby/object:Gem::Requirement
99
- requirements:
100
- - - "~>"
101
- - !ruby/object:Gem::Version
102
- version: 0.22.0
103
- type: :development
104
- prerelease: false
105
- version_requirements: !ruby/object:Gem::Requirement
106
- requirements:
107
- - - "~>"
108
- - !ruby/object:Gem::Version
109
- version: 0.22.0
110
- - !ruby/object:Gem::Dependency
111
- name: simplecov-cobertura
112
- requirement: !ruby/object:Gem::Requirement
113
- requirements:
114
- - - "~>"
115
- - !ruby/object:Gem::Version
116
- version: '3.0'
117
- type: :development
118
- prerelease: false
119
- version_requirements: !ruby/object:Gem::Requirement
120
- requirements:
121
- - - "~>"
122
- - !ruby/object:Gem::Version
123
- version: '3.0'
124
- - !ruby/object:Gem::Dependency
125
- name: timecop
126
- requirement: !ruby/object:Gem::Requirement
127
- requirements:
128
- - - "~>"
129
- - !ruby/object:Gem::Version
130
- version: 0.9.10
131
- type: :development
132
- prerelease: false
133
- version_requirements: !ruby/object:Gem::Requirement
134
- requirements:
135
- - - "~>"
136
- - !ruby/object:Gem::Version
137
- version: 0.9.10
138
- description: Ruby SDK for an the specifications for the open standard of feature flag
139
- management
11
+ dependencies: []
12
+ description: Ruby SDK for the OpenFeature specification, an open standard for feature
13
+ flag management
140
14
  email:
141
15
  - cncf-openfeature-contributors@lists.cncf.io
142
16
  executables: []
@@ -146,9 +20,9 @@ files:
146
20
  - ".release-please-manifest.json"
147
21
  - ".rspec"
148
22
  - ".ruby-version"
149
- - ".simplecov"
150
23
  - ".standard.yml"
151
24
  - ".tool-versions"
25
+ - ".yardopts"
152
26
  - CHANGELOG.md
153
27
  - CLAUDE.md
154
28
  - CODEOWNERS
@@ -159,9 +33,12 @@ files:
159
33
  - LICENSE
160
34
  - README.md
161
35
  - Rakefile
36
+ - SECURITY.md
37
+ - Steepfile
162
38
  - cucumber.yml
163
- - docs/plans/2026-03-07-telemetry-utility-design.md
164
- - docs/plans/2026-03-07-telemetry-utility-plan.md
39
+ - examples/basic_usage.rb
40
+ - examples/custom_provider.rb
41
+ - examples/rails_integration.rb
165
42
  - lib/open_feature/sdk.rb
166
43
  - lib/open_feature/sdk/api.rb
167
44
  - lib/open_feature/sdk/client.rb
@@ -170,6 +47,7 @@ files:
170
47
  - lib/open_feature/sdk/evaluation_context.rb
171
48
  - lib/open_feature/sdk/evaluation_context_builder.rb
172
49
  - lib/open_feature/sdk/evaluation_details.rb
50
+ - lib/open_feature/sdk/evaluation_error.rb
173
51
  - lib/open_feature/sdk/event_dispatcher.rb
174
52
  - lib/open_feature/sdk/hooks.rb
175
53
  - lib/open_feature/sdk/hooks/hints.rb
@@ -194,17 +72,53 @@ files:
194
72
  - lib/open_feature/sdk/tracking_event_details.rb
195
73
  - lib/open_feature/sdk/transaction_context_propagator.rb
196
74
  - lib/open_feature/sdk/version.rb
75
+ - openfeature-sdk.gemspec
76
+ - rbs_collection.lock.yaml
77
+ - rbs_collection.yaml
197
78
  - release-please-config.json
198
79
  - renovate.json
199
- homepage: https://github.com/open-feature/openfeature-ruby
80
+ - sig/open_feature/sdk.rbs
81
+ - sig/open_feature/sdk/api.rbs
82
+ - sig/open_feature/sdk/client.rbs
83
+ - sig/open_feature/sdk/client_metadata.rbs
84
+ - sig/open_feature/sdk/configuration.rbs
85
+ - sig/open_feature/sdk/evaluation_context.rbs
86
+ - sig/open_feature/sdk/evaluation_context_builder.rbs
87
+ - sig/open_feature/sdk/evaluation_details.rbs
88
+ - sig/open_feature/sdk/evaluation_error.rbs
89
+ - sig/open_feature/sdk/event_dispatcher.rbs
90
+ - sig/open_feature/sdk/hooks/hints.rbs
91
+ - sig/open_feature/sdk/hooks/hook.rbs
92
+ - sig/open_feature/sdk/hooks/hook_context.rbs
93
+ - sig/open_feature/sdk/hooks/hook_executor.rbs
94
+ - sig/open_feature/sdk/hooks/logging_hook.rbs
95
+ - sig/open_feature/sdk/provider.rbs
96
+ - sig/open_feature/sdk/provider/error_code.rbs
97
+ - sig/open_feature/sdk/provider/event_emitter.rbs
98
+ - sig/open_feature/sdk/provider/in_memory_provider.rbs
99
+ - sig/open_feature/sdk/provider/no_op_provider.rbs
100
+ - sig/open_feature/sdk/provider/provider_metadata.rbs
101
+ - sig/open_feature/sdk/provider/reason.rbs
102
+ - sig/open_feature/sdk/provider/resolution_details.rbs
103
+ - sig/open_feature/sdk/provider_event.rbs
104
+ - sig/open_feature/sdk/provider_initialization_error.rbs
105
+ - sig/open_feature/sdk/provider_state.rbs
106
+ - sig/open_feature/sdk/provider_state_registry.rbs
107
+ - sig/open_feature/sdk/telemetry.rbs
108
+ - sig/open_feature/sdk/thread_local_transaction_context_propagator.rbs
109
+ - sig/open_feature/sdk/tracking_event_details.rbs
110
+ - sig/open_feature/sdk/transaction_context_propagator.rbs
111
+ - sig/open_feature/sdk/version.rbs
112
+ homepage: https://github.com/open-feature/ruby-sdk
200
113
  licenses:
201
114
  - Apache-2.0
202
115
  metadata:
203
- homepage_uri: https://github.com/open-feature/openfeature-ruby
204
- source_code_uri: https://github.com/open-feature/openfeature-ruby
205
- changelog_uri: https://github.com/open-feature/openfeature-ruby/blob/main/CHANGELOG.md
206
- bug_tracker_uri: https://github.com/open-feature/openfeature-ruby/issues
207
- documentation_uri: https://github.com/open-feature/openfeature-ruby/README.md
116
+ homepage_uri: https://github.com/open-feature/ruby-sdk
117
+ source_code_uri: https://github.com/open-feature/ruby-sdk
118
+ changelog_uri: https://github.com/open-feature/ruby-sdk/blob/main/CHANGELOG.md
119
+ bug_tracker_uri: https://github.com/open-feature/ruby-sdk/issues
120
+ documentation_uri: https://github.com/open-feature/ruby-sdk#readme
121
+ rubygems_mfa_required: 'true'
208
122
  rdoc_options: []
209
123
  require_paths:
210
124
  - lib
@@ -219,7 +133,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
219
133
  - !ruby/object:Gem::Version
220
134
  version: '0'
221
135
  requirements: []
222
- rubygems_version: 4.0.3
136
+ rubygems_version: 4.0.20
223
137
  specification_version: 4
224
138
  summary: OpenFeature SDK for Ruby
225
139
  test_files: []
data/.simplecov DELETED
@@ -1,12 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "simplecov-cobertura"
4
-
5
- SimpleCov.start do
6
- add_filter "/spec/"
7
- if ENV["CI"] == "true"
8
- formatter SimpleCov::Formatter::CoberturaFormatter
9
- else
10
- formatter SimpleCov::Formatter::HTMLFormatter
11
- end
12
- end
@@ -1,98 +0,0 @@
1
- # Telemetry Utility Design
2
-
3
- ## Overview
4
-
5
- Add an OTel-compatible telemetry utility to the OpenFeature Ruby SDK that creates
6
- structured evaluation events from hook context and evaluation details. This utility
7
- is dependency-free (no OTel gem required) and follows the pattern established by
8
- the Go SDK's `telemetry` package.
9
-
10
- Addresses: https://github.com/open-feature/ruby-sdk/issues/176
11
-
12
- ## References
13
-
14
- - [OpenFeature Spec Appendix D (Observability)](https://openfeature.dev/specification/appendix-d/)
15
- - [OTel Semantic Conventions for Feature Flags](https://opentelemetry.io/docs/specs/semconv/feature-flags/feature-flags-logs/)
16
- - [Go SDK telemetry package](https://github.com/open-feature/go-sdk/tree/main/openfeature/telemetry)
17
- - [JS SDK reference PR](https://github.com/open-feature/js-sdk/pull/1120)
18
-
19
- ## Design Decisions
20
-
21
- 1. **Single public method** accepting `hook_context:` and `evaluation_details:` keyword
22
- arguments — mirrors the `finally` hook stage signature for zero-friction integration.
23
- 2. **Returns a Struct** (`EvaluationEvent`) with `name` and `attributes` fields — matches
24
- the SDK's existing Struct conventions (`ResolutionDetails`, `ClientMetadata`, etc.).
25
- 3. **Constants in the Telemetry module directly** — flat namespace matching Go SDK and
26
- existing Ruby SDK patterns (e.g., `Provider::Reason`).
27
- 4. **Hard-coded metadata mappings only** — maps `contextId`, `flagSetId`, `version` from
28
- flag metadata to OTel keys. Unknown metadata keys are ignored. Custom attributes can
29
- be added via hooks in ruby-sdk-contrib.
30
- 5. **No third-party dependencies** — pure data transformation using only standard library.
31
-
32
- ## File Structure
33
-
34
- - `lib/open_feature/sdk/telemetry.rb` — module with constants, struct, and utility function
35
- - `spec/open_feature/sdk/telemetry_spec.rb` — tests
36
- - `lib/open_feature/sdk.rb` — add `require_relative "sdk/telemetry"`
37
-
38
- ## Constants
39
-
40
- ```ruby
41
- EVENT_NAME = "feature_flag.evaluation"
42
-
43
- FLAG_KEY = "feature_flag.key"
44
- CONTEXT_ID_KEY = "feature_flag.context.id"
45
- ERROR_MESSAGE_KEY = "error.message"
46
- ERROR_TYPE_KEY = "error.type"
47
- PROVIDER_NAME_KEY = "feature_flag.provider.name"
48
- RESULT_REASON_KEY = "feature_flag.result.reason"
49
- RESULT_VALUE_KEY = "feature_flag.result.value"
50
- RESULT_VARIANT_KEY = "feature_flag.result.variant"
51
- FLAG_SET_ID_KEY = "feature_flag.set.id"
52
- VERSION_KEY = "feature_flag.version"
53
- ```
54
-
55
- ## Public API
56
-
57
- ```ruby
58
- OpenFeature::SDK::Telemetry.create_evaluation_event(
59
- hook_context:, # Hooks::HookContext
60
- evaluation_details: # EvaluationDetails or nil
61
- ) # => EvaluationEvent
62
- ```
63
-
64
- Returns `EvaluationEvent = Struct.new(:name, :attributes, keyword_init: true)`.
65
-
66
- ## Attribute Population Rules
67
-
68
- | Attribute | Source | Condition |
69
- |-----------|--------|-----------|
70
- | `feature_flag.key` | `hook_context.flag_key` | Always |
71
- | `feature_flag.provider.name` | `hook_context.provider_metadata.name` | When present |
72
- | `feature_flag.result.variant` | `evaluation_details.variant` | When present (takes precedence over value) |
73
- | `feature_flag.result.value` | `evaluation_details.value` | Only when variant is nil |
74
- | `feature_flag.result.reason` | `evaluation_details.reason.downcase` | When present |
75
- | `error.type` | `evaluation_details.error_code.downcase` | When error occurred |
76
- | `error.message` | `evaluation_details.error_message` | When error occurred |
77
- | `feature_flag.context.id` | `targeting_key` or metadata `contextId` | Metadata takes precedence |
78
- | `feature_flag.set.id` | metadata `flagSetId` | When present in flag_metadata |
79
- | `feature_flag.version` | metadata `version` | When present in flag_metadata |
80
-
81
- ## Error Handling
82
-
83
- No defensive `rescue` in the utility — it is a pure data transformation. Nil inputs
84
- are handled via guard clauses. The calling hook is responsible for exception safety
85
- (consistent with the existing hook executor pattern).
86
-
87
- ## Test Plan
88
-
89
- 1. Happy path with all attributes populated
90
- 2. Variant vs value precedence
91
- 3. Enum downcasing (reason and error_code)
92
- 4. Error attributes present only on error
93
- 5. Nil evaluation_details
94
- 6. Nil/empty flag_metadata
95
- 7. Metadata contextId overrides targeting_key
96
- 8. Targeting key fallback when no contextId
97
- 9. Unknown metadata keys ignored
98
- 10. Return type verification