openfeature-sdk 0.6.4 → 0.6.5

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 (56) hide show
  1. checksums.yaml +4 -4
  2. data/.release-please-manifest.json +1 -1
  3. data/.ruby-version +1 -1
  4. data/.simplecov +1 -0
  5. data/.tool-versions +1 -1
  6. data/.yardopts +5 -0
  7. data/CHANGELOG.md +7 -0
  8. data/CLAUDE.md +3 -0
  9. data/CONTRIBUTING.md +15 -1
  10. data/Gemfile +17 -2
  11. data/Gemfile.lock +72 -13
  12. data/README.md +14 -2
  13. data/Rakefile +14 -0
  14. data/SECURITY.md +10 -0
  15. data/Steepfile +7 -0
  16. data/examples/basic_usage.rb +22 -0
  17. data/examples/custom_provider.rb +56 -0
  18. data/examples/rails_integration.rb +60 -0
  19. data/lib/open_feature/sdk/version.rb +1 -1
  20. data/openfeature-sdk.gemspec +34 -0
  21. data/rbs_collection.lock.yaml +292 -0
  22. data/rbs_collection.yaml +14 -0
  23. data/sig/open_feature/sdk/api.rbs +35 -0
  24. data/sig/open_feature/sdk/client.rbs +49 -0
  25. data/sig/open_feature/sdk/client_metadata.rbs +11 -0
  26. data/sig/open_feature/sdk/configuration.rbs +43 -0
  27. data/sig/open_feature/sdk/evaluation_context.rbs +19 -0
  28. data/sig/open_feature/sdk/evaluation_context_builder.rbs +7 -0
  29. data/sig/open_feature/sdk/evaluation_details.rbs +19 -0
  30. data/sig/open_feature/sdk/event_dispatcher.rbs +24 -0
  31. data/sig/open_feature/sdk/hooks/hints.rbs +30 -0
  32. data/sig/open_feature/sdk/hooks/hook.rbs +19 -0
  33. data/sig/open_feature/sdk/hooks/hook_context.rbs +18 -0
  34. data/sig/open_feature/sdk/hooks/hook_executor.rbs +20 -0
  35. data/sig/open_feature/sdk/hooks/logging_hook.rbs +25 -0
  36. data/sig/open_feature/sdk/provider/error_code.rbs +16 -0
  37. data/sig/open_feature/sdk/provider/event_emitter.rbs +16 -0
  38. data/sig/open_feature/sdk/provider/in_memory_provider.rbs +35 -0
  39. data/sig/open_feature/sdk/provider/no_op_provider.rbs +25 -0
  40. data/sig/open_feature/sdk/provider/provider_metadata.rbs +11 -0
  41. data/sig/open_feature/sdk/provider/reason.rbs +17 -0
  42. data/sig/open_feature/sdk/provider/resolution_details.rbs +19 -0
  43. data/sig/open_feature/sdk/provider.rbs +24 -0
  44. data/sig/open_feature/sdk/provider_event.rbs +12 -0
  45. data/sig/open_feature/sdk/provider_initialization_error.rbs +11 -0
  46. data/sig/open_feature/sdk/provider_state.rbs +13 -0
  47. data/sig/open_feature/sdk/provider_state_registry.rbs +22 -0
  48. data/sig/open_feature/sdk/telemetry.rbs +29 -0
  49. data/sig/open_feature/sdk/thread_local_transaction_context_propagator.rbs +12 -0
  50. data/sig/open_feature/sdk/tracking_event_details.rbs +10 -0
  51. data/sig/open_feature/sdk/transaction_context_propagator.rbs +11 -0
  52. data/sig/open_feature/sdk/version.rbs +5 -0
  53. data/sig/open_feature/sdk.rbs +22 -0
  54. metadata +52 -139
  55. data/docs/plans/2026-03-07-telemetry-utility-design.md +0 -98
  56. data/docs/plans/2026-03-07-telemetry-utility-plan.md +0 -578
@@ -0,0 +1,35 @@
1
+ module OpenFeature
2
+ module SDK
3
+ module Provider
4
+ class InMemoryProvider
5
+ include Provider::EventEmitter
6
+
7
+ NAME: String
8
+
9
+ attr_reader metadata: ProviderMetadata
10
+
11
+ def initialize: (?Hash[String, untyped] flags) -> void
12
+
13
+ def init: (?EvaluationContext? evaluation_context) -> void
14
+ def shutdown: () -> void
15
+
16
+ def add_flag: (flag_key: String, value: untyped) -> void
17
+ def update_flags: (Hash[String, untyped] new_flags) -> void
18
+
19
+ def fetch_boolean_value: (flag_key: String, default_value: bool, ?evaluation_context: EvaluationContext?) -> ResolutionDetails
20
+ def fetch_string_value: (flag_key: String, default_value: String, ?evaluation_context: EvaluationContext?) -> ResolutionDetails
21
+ def fetch_number_value: (flag_key: String, default_value: Numeric, ?evaluation_context: EvaluationContext?) -> ResolutionDetails
22
+ def fetch_integer_value: (flag_key: String, default_value: Integer, ?evaluation_context: EvaluationContext?) -> ResolutionDetails
23
+ def fetch_float_value: (flag_key: String, default_value: Float, ?evaluation_context: EvaluationContext?) -> ResolutionDetails
24
+ def fetch_object_value: (flag_key: String, default_value: Array[untyped] | Hash[untyped, untyped], ?evaluation_context: EvaluationContext?) -> ResolutionDetails
25
+
26
+ private
27
+
28
+ attr_reader flags: Hash[String, untyped]
29
+
30
+ def fetch_value: (flag_key: String, default_value: untyped, evaluation_context: EvaluationContext?) -> ResolutionDetails
31
+ def emit_provider_changed: (Array[String] flag_keys) -> void
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,25 @@
1
+ module OpenFeature
2
+ module SDK
3
+ module Provider
4
+ class NoOpProvider
5
+ REASON_NO_OP: String
6
+ NAME: String
7
+
8
+ attr_reader metadata: ProviderMetadata
9
+
10
+ def initialize: () -> void
11
+
12
+ def fetch_boolean_value: (flag_key: String, default_value: bool, ?evaluation_context: EvaluationContext?) -> ResolutionDetails
13
+ def fetch_string_value: (flag_key: String, default_value: String, ?evaluation_context: EvaluationContext?) -> ResolutionDetails
14
+ def fetch_number_value: (flag_key: String, default_value: Numeric, ?evaluation_context: EvaluationContext?) -> ResolutionDetails
15
+ def fetch_integer_value: (flag_key: String, default_value: Integer, ?evaluation_context: EvaluationContext?) -> ResolutionDetails
16
+ def fetch_float_value: (flag_key: String, default_value: Float, ?evaluation_context: EvaluationContext?) -> ResolutionDetails
17
+ def fetch_object_value: (flag_key: String, default_value: Array[untyped] | Hash[untyped, untyped], ?evaluation_context: EvaluationContext?) -> ResolutionDetails
18
+
19
+ private
20
+
21
+ def no_op: (untyped default_value) -> ResolutionDetails
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,11 @@
1
+ module OpenFeature
2
+ module SDK
3
+ module Provider
4
+ class ProviderMetadata < Struct[untyped]
5
+ attr_accessor name: String?
6
+
7
+ def initialize: (?name: String?) -> void
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,17 @@
1
+ module OpenFeature
2
+ module SDK
3
+ module Provider
4
+ module Reason
5
+ STATIC: String
6
+ DEFAULT: String
7
+ TARGETING_MATCH: String
8
+ SPLIT: String
9
+ CACHED: String
10
+ DISABLED: String
11
+ UNKNOWN: String
12
+ STALE: String
13
+ ERROR: String
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,19 @@
1
+ module OpenFeature
2
+ module SDK
3
+ module Provider
4
+ EMPTY_FLAG_METADATA: Hash[String, untyped]
5
+
6
+ class ResolutionDetails < Struct[untyped]
7
+ attr_accessor value: untyped
8
+ attr_accessor reason: String?
9
+ attr_accessor variant: String?
10
+ attr_accessor error_code: String?
11
+ attr_accessor error_message: String?
12
+
13
+ def initialize: (?value: untyped, ?reason: String?, ?variant: String?, ?error_code: String?, ?error_message: String?, ?flag_metadata: Hash[String, untyped]?) -> void
14
+
15
+ def flag_metadata: () -> Hash[String, untyped]
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,24 @@
1
+ module OpenFeature
2
+ module SDK
3
+ module Provider
4
+ interface _Provider
5
+ def fetch_boolean_value: (flag_key: String, default_value: bool, ?evaluation_context: EvaluationContext?) -> Provider::ResolutionDetails
6
+ def fetch_string_value: (flag_key: String, default_value: String, ?evaluation_context: EvaluationContext?) -> Provider::ResolutionDetails
7
+ def fetch_number_value: (flag_key: String, default_value: Numeric, ?evaluation_context: EvaluationContext?) -> Provider::ResolutionDetails
8
+ def fetch_integer_value: (flag_key: String, default_value: Integer, ?evaluation_context: EvaluationContext?) -> Provider::ResolutionDetails
9
+ def fetch_float_value: (flag_key: String, default_value: Float, ?evaluation_context: EvaluationContext?) -> Provider::ResolutionDetails
10
+ def fetch_object_value: (flag_key: String, default_value: Array[untyped] | Hash[untyped, untyped], ?evaluation_context: EvaluationContext?) -> Provider::ResolutionDetails
11
+ end
12
+
13
+ interface _LifecycleProvider
14
+ def init: (?EvaluationContext? evaluation_context) -> void
15
+ def shutdown: () -> void
16
+ def metadata: () -> ProviderMetadata
17
+ end
18
+
19
+ interface _TrackableProvider
20
+ def track: (String tracking_event_name, ?evaluation_context: EvaluationContext?, ?tracking_event_details: TrackingEventDetails?) -> void
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,12 @@
1
+ module OpenFeature
2
+ module SDK
3
+ module ProviderEvent
4
+ PROVIDER_READY: String
5
+ PROVIDER_ERROR: String
6
+ PROVIDER_CONFIGURATION_CHANGED: String
7
+ PROVIDER_STALE: String
8
+
9
+ ALL_EVENTS: Array[String]
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,11 @@
1
+ module OpenFeature
2
+ module SDK
3
+ class ProviderInitializationError < StandardError
4
+ attr_reader provider: untyped
5
+ attr_reader original_error: Exception?
6
+ attr_reader error_code: String
7
+
8
+ def initialize: (String message, ?provider: untyped, ?original_error: Exception?, ?error_code: String) -> void
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,13 @@
1
+ module OpenFeature
2
+ module SDK
3
+ module ProviderState
4
+ NOT_READY: String
5
+ READY: String
6
+ ERROR: String
7
+ STALE: String
8
+ FATAL: String
9
+
10
+ ALL_STATES: Array[String]
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,22 @@
1
+ module OpenFeature
2
+ module SDK
3
+ class ProviderStateRegistry
4
+ def initialize: () -> void
5
+
6
+ def set_initial_state: (untyped provider, ?String state) -> void
7
+ def update_state_from_event: (untyped provider, String event_type, ?Hash[Symbol, untyped]? event_details) -> String
8
+ def get_state: (untyped provider) -> String
9
+ def get_details: (untyped provider) -> Hash[Symbol, untyped]
10
+ def remove_provider: (untyped provider) -> void
11
+ def tracked?: (untyped provider) -> bool
12
+ def ready?: (untyped provider) -> bool
13
+ def error?: (untyped provider) -> bool
14
+ def clear: () -> void
15
+
16
+ private
17
+
18
+ def state_from_event: (String event_type, ?Hash[Symbol, untyped]? event_details) -> String?
19
+ def state_from_error_event: (Hash[Symbol, untyped]? event_details) -> String
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,29 @@
1
+ module OpenFeature
2
+ module SDK
3
+ module Telemetry
4
+ EVENT_NAME: String
5
+
6
+ FLAG_KEY: String
7
+ CONTEXT_ID_KEY: String
8
+ ERROR_MESSAGE_KEY: String
9
+ ERROR_TYPE_KEY: String
10
+ PROVIDER_NAME_KEY: String
11
+ RESULT_REASON_KEY: String
12
+ RESULT_VALUE_KEY: String
13
+ RESULT_VARIANT_KEY: String
14
+ FLAG_SET_ID_KEY: String
15
+ VERSION_KEY: String
16
+
17
+ METADATA_KEY_MAP: Hash[String, String]
18
+
19
+ class EvaluationEvent < Struct[untyped]
20
+ attr_accessor name: String
21
+ attr_accessor attributes: Hash[String, untyped]
22
+
23
+ def initialize: (?name: String, ?attributes: Hash[String, untyped]) -> void
24
+ end
25
+
26
+ def self.create_evaluation_event: (hook_context: Hooks::HookContext, evaluation_details: EvaluationDetails?) -> EvaluationEvent
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,12 @@
1
+ module OpenFeature
2
+ module SDK
3
+ class ThreadLocalTransactionContextPropagator
4
+ include TransactionContextPropagator
5
+
6
+ THREAD_KEY: Symbol
7
+
8
+ def set_transaction_context: (EvaluationContext evaluation_context) -> void
9
+ def get_transaction_context: () -> EvaluationContext?
10
+ end
11
+ end
12
+ end
@@ -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.5
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: []
@@ -149,6 +23,7 @@ files:
149
23
  - ".simplecov"
150
24
  - ".standard.yml"
151
25
  - ".tool-versions"
26
+ - ".yardopts"
152
27
  - CHANGELOG.md
153
28
  - CLAUDE.md
154
29
  - CODEOWNERS
@@ -159,9 +34,12 @@ files:
159
34
  - LICENSE
160
35
  - README.md
161
36
  - Rakefile
37
+ - SECURITY.md
38
+ - Steepfile
162
39
  - cucumber.yml
163
- - docs/plans/2026-03-07-telemetry-utility-design.md
164
- - docs/plans/2026-03-07-telemetry-utility-plan.md
40
+ - examples/basic_usage.rb
41
+ - examples/custom_provider.rb
42
+ - examples/rails_integration.rb
165
43
  - lib/open_feature/sdk.rb
166
44
  - lib/open_feature/sdk/api.rb
167
45
  - lib/open_feature/sdk/client.rb
@@ -194,17 +72,52 @@ 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/event_dispatcher.rbs
89
+ - sig/open_feature/sdk/hooks/hints.rbs
90
+ - sig/open_feature/sdk/hooks/hook.rbs
91
+ - sig/open_feature/sdk/hooks/hook_context.rbs
92
+ - sig/open_feature/sdk/hooks/hook_executor.rbs
93
+ - sig/open_feature/sdk/hooks/logging_hook.rbs
94
+ - sig/open_feature/sdk/provider.rbs
95
+ - sig/open_feature/sdk/provider/error_code.rbs
96
+ - sig/open_feature/sdk/provider/event_emitter.rbs
97
+ - sig/open_feature/sdk/provider/in_memory_provider.rbs
98
+ - sig/open_feature/sdk/provider/no_op_provider.rbs
99
+ - sig/open_feature/sdk/provider/provider_metadata.rbs
100
+ - sig/open_feature/sdk/provider/reason.rbs
101
+ - sig/open_feature/sdk/provider/resolution_details.rbs
102
+ - sig/open_feature/sdk/provider_event.rbs
103
+ - sig/open_feature/sdk/provider_initialization_error.rbs
104
+ - sig/open_feature/sdk/provider_state.rbs
105
+ - sig/open_feature/sdk/provider_state_registry.rbs
106
+ - sig/open_feature/sdk/telemetry.rbs
107
+ - sig/open_feature/sdk/thread_local_transaction_context_propagator.rbs
108
+ - sig/open_feature/sdk/tracking_event_details.rbs
109
+ - sig/open_feature/sdk/transaction_context_propagator.rbs
110
+ - sig/open_feature/sdk/version.rbs
111
+ homepage: https://github.com/open-feature/ruby-sdk
200
112
  licenses:
201
113
  - Apache-2.0
202
114
  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
115
+ homepage_uri: https://github.com/open-feature/ruby-sdk
116
+ source_code_uri: https://github.com/open-feature/ruby-sdk
117
+ changelog_uri: https://github.com/open-feature/ruby-sdk/blob/main/CHANGELOG.md
118
+ bug_tracker_uri: https://github.com/open-feature/ruby-sdk/issues
119
+ documentation_uri: https://github.com/open-feature/ruby-sdk#readme
120
+ rubygems_mfa_required: 'true'
208
121
  rdoc_options: []
209
122
  require_paths:
210
123
  - lib
@@ -219,7 +132,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
219
132
  - !ruby/object:Gem::Version
220
133
  version: '0'
221
134
  requirements: []
222
- rubygems_version: 4.0.3
135
+ rubygems_version: 4.0.6
223
136
  specification_version: 4
224
137
  summary: OpenFeature SDK for Ruby
225
138
  test_files: []
@@ -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