schematichq 1.4.8 → 1.4.10

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 (100) hide show
  1. checksums.yaml +4 -4
  2. data/.fern/metadata.json +3 -3
  3. data/.fern/replay.lock +350 -2
  4. data/WASM_VERSION +1 -1
  5. data/lib/schematic/billing/types/create_invoice_request_body.rb +2 -0
  6. data/lib/schematic/catalogs/client.rb +480 -0
  7. data/lib/schematic/catalogs/types/create_catalog_request_body.rb +13 -0
  8. data/lib/schematic/catalogs/types/create_catalog_response.rb +12 -0
  9. data/lib/schematic/catalogs/types/delete_catalog_response.rb +12 -0
  10. data/lib/schematic/catalogs/types/get_catalog_response.rb +12 -0
  11. data/lib/schematic/catalogs/types/get_configuration_response.rb +12 -0
  12. data/lib/schematic/catalogs/types/get_credit_bundles_in_catalog_response.rb +12 -0
  13. data/lib/schematic/catalogs/types/get_derived_features_response.rb +12 -0
  14. data/lib/schematic/catalogs/types/get_plans_in_catalog_response.rb +12 -0
  15. data/lib/schematic/catalogs/types/list_catalogs_params.rb +15 -0
  16. data/lib/schematic/catalogs/types/list_catalogs_request.rb +14 -0
  17. data/lib/schematic/catalogs/types/list_catalogs_response.rb +12 -0
  18. data/lib/schematic/catalogs/types/update_catalog_configuration_request_body.rb +20 -0
  19. data/lib/schematic/catalogs/types/update_catalog_request_body.rb +14 -0
  20. data/lib/schematic/catalogs/types/update_catalog_response.rb +12 -0
  21. data/lib/schematic/catalogs/types/update_configuration_response.rb +12 -0
  22. data/lib/schematic/checkout/client.rb +69 -0
  23. data/lib/schematic/checkout/types/get_company_billing_details_response.rb +12 -0
  24. data/lib/schematic/checkout/types/update_company_billing_details_request_body.rb +15 -0
  25. data/lib/schematic/checkout/types/update_company_billing_details_response.rb +12 -0
  26. data/lib/schematic/client.rb +6 -1
  27. data/lib/schematic/components/client.rb +37 -0
  28. data/lib/schematic/components/types/bind_catalog_request_body.rb +12 -0
  29. data/lib/schematic/components/types/bind_catalog_response.rb +12 -0
  30. data/lib/schematic/dataexports/client.rb +76 -0
  31. data/lib/schematic/dataexports/types/create_data_export_request_body.rb +3 -3
  32. data/lib/schematic/dataexports/types/get_data_export_response.rb +12 -0
  33. data/lib/schematic/dataexports/types/list_data_exports_params.rb +15 -0
  34. data/lib/schematic/dataexports/types/list_data_exports_request.rb +14 -0
  35. data/lib/schematic/dataexports/types/list_data_exports_response.rb +12 -0
  36. data/lib/schematic/entitlements/types/create_billing_linked_plan_entitlement_request_body.rb +1 -0
  37. data/lib/schematic/entitlements/types/create_plan_entitlement_request_body.rb +1 -0
  38. data/lib/schematic/entitlements/types/update_plan_entitlement_request_body.rb +1 -0
  39. data/lib/schematic/planbundle/types/create_custom_plan_bundle_request_body.rb +1 -0
  40. data/lib/schematic/planbundle/types/create_plan_bundle_request_body.rb +0 -1
  41. data/lib/schematic/planbundle/types/update_plan_bundle_request_body.rb +0 -1
  42. data/lib/schematic/rules_engine.rb +11 -0
  43. data/lib/schematic/types/account_member_permission.rb +1 -0
  44. data/lib/schematic/types/audit_log_export_metadata.rb +13 -0
  45. data/lib/schematic/types/billing_plan_credit_grant_reset_cadence.rb +2 -0
  46. data/lib/schematic/types/catalog_config_ordered_bundle.rb +9 -0
  47. data/lib/schematic/types/catalog_config_ordered_bundle_response_data.rb +9 -0
  48. data/lib/schematic/types/catalog_config_ordered_entitlement.rb +10 -0
  49. data/lib/schematic/types/catalog_config_ordered_entitlement_response_data.rb +10 -0
  50. data/lib/schematic/types/catalog_config_ordered_plan.rb +10 -0
  51. data/lib/schematic/types/catalog_config_ordered_plan_response_data.rb +10 -0
  52. data/lib/schematic/types/catalog_configuration_response_data.rb +19 -0
  53. data/lib/schematic/types/catalog_credit_bundle_i_ds_response_data.rb +9 -0
  54. data/lib/schematic/types/catalog_derived_feature_response_data.rb +11 -0
  55. data/lib/schematic/types/catalog_derived_features_response_data.rb +9 -0
  56. data/lib/schematic/types/catalog_plan_i_ds_response_data.rb +9 -0
  57. data/lib/schematic/types/catalog_response_data.rb +22 -0
  58. data/lib/schematic/types/company_billing_address_view.rb +14 -0
  59. data/lib/schematic/types/company_billing_checkout_settings.rb +11 -0
  60. data/lib/schematic/types/company_billing_details_response_data.rb +13 -0
  61. data/lib/schematic/types/company_billing_details_view.rb +13 -0
  62. data/lib/schematic/types/company_feature_usage_export_metadata.rb +25 -0
  63. data/lib/schematic/types/company_plan_detail_response_data.rb +1 -0
  64. data/lib/schematic/types/component_response_data.rb +1 -0
  65. data/lib/schematic/types/create_entitlement_in_bundle_request_body.rb +1 -0
  66. data/lib/schematic/types/credits_auto_topup_success.rb +12 -0
  67. data/lib/schematic/types/credits_credit_purchase_success.rb +14 -0
  68. data/lib/schematic/types/credits_webhook_company_summary.rb +10 -0
  69. data/lib/schematic/types/credits_webhook_credit_summary.rb +10 -0
  70. data/lib/schematic/types/customer_billing_address.rb +14 -0
  71. data/lib/schematic/types/data_export_metadata.rb +14 -0
  72. data/lib/schematic/types/data_export_output_file_type.rb +3 -14
  73. data/lib/schematic/types/data_export_response_data.rb +3 -3
  74. data/lib/schematic/types/data_export_type.rb +3 -14
  75. data/lib/schematic/types/event_body.rb +1 -0
  76. data/lib/schematic/types/event_body_inference.rb +22 -0
  77. data/lib/schematic/types/event_type.rb +1 -0
  78. data/lib/schematic/types/feature_entitlement.rb +1 -0
  79. data/lib/schematic/types/invoice_request_body.rb +2 -0
  80. data/lib/schematic/types/invoice_response_data.rb +2 -0
  81. data/lib/schematic/types/plan_bundle_response_data.rb +0 -1
  82. data/lib/schematic/types/plan_catalog_membership_response_data.rb +10 -0
  83. data/lib/schematic/types/plan_detail_response_data.rb +1 -0
  84. data/lib/schematic/types/plan_entitlement_response_data.rb +1 -0
  85. data/lib/schematic/types/plan_group_plan_detail_response_data.rb +1 -0
  86. data/lib/schematic/types/plan_view_public_response_data.rb +1 -0
  87. data/lib/schematic/types/preview_subscription_discount_response_data.rb +19 -0
  88. data/lib/schematic/types/preview_subscription_finance_response_data.rb +2 -0
  89. data/lib/schematic/types/rulesengine_feature_entitlement.rb +1 -0
  90. data/lib/schematic/types/rulesengine_warning_tier.rb +10 -0
  91. data/lib/schematic/types/upsert_company_request_body.rb +2 -0
  92. data/lib/schematic/types/warning_tier.rb +10 -0
  93. data/lib/schematic/types/warning_tier_request_body.rb +10 -0
  94. data/lib/schematic/types/warning_tier_response_data.rb +11 -0
  95. data/lib/schematic/types/webhook_request_type.rb +2 -0
  96. data/lib/schematic/version.rb +1 -1
  97. data/lib/schematic/wasm/rulesengine.wasm +0 -0
  98. data/lib/schematic.rb +92 -36
  99. data/reference.md +1290 -83
  100. metadata +58 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 36bcd47c40d3cd4cf1406cd9c468fdb825e820ea052dd6375b06fd0fd2a28026
4
- data.tar.gz: a9469ee307dcd2f19271d563a948b33d8abafffae8efa933b80eeeaa71c3708e
3
+ metadata.gz: 677e9663f6096839ed9c6bd6cfcc614d5591878ab699d4c3ea042a5517d4be13
4
+ data.tar.gz: b585b4c5f09b418cee556f125d195f2c16fd9137636c1d38208f90012f85f5f5
5
5
  SHA512:
6
- metadata.gz: 266d456ba8ee109c9e666fd1754b4f88f2b2de54cd893a5f1341265e58dd5da8b399dcf217c56e875fed6db60cbbeee34c400a30a47afdcd4828da9644e5d582
7
- data.tar.gz: 18a408a807a8c49766a96bf2fa84633810ec06119552298e67afc991ce66d1cedb44203d75a247ae8d79c2d12c22f9d32632febff24102bc0a7808d00bbdee58
6
+ metadata.gz: d0b82a52c15011754abfc68b7e76a8ab65a27932afa63d1036b86b59e81ff41099e14e18335555762e1e7f9c04bde39628677f477c5a8a300623db8f121bdf80
7
+ data.tar.gz: f26162008e22f054c4465d307f07bc7c237cd88940e295ab5229163330d0620df1c373a488dd160be3ec5b13214c14645c31a6fb0f0c1acb5caf2a67db18e3e4
data/.fern/metadata.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "cliVersion": "5.6.0",
2
+ "cliVersion": "5.50.0",
3
3
  "generatorName": "fernapi/fern-ruby-sdk",
4
4
  "generatorVersion": "1.1.13",
5
5
  "generatorConfig": {
@@ -13,6 +13,6 @@
13
13
  "webrick": ">= 1.0"
14
14
  }
15
15
  },
16
- "originGitCommit": "1c3370c354acf100ad68319d09b964e93635a3d5",
17
- "sdkVersion": "1.4.8"
16
+ "originGitCommit": "75191b40ce7af084ca4fb11f623ab59c57cf97e3",
17
+ "sdkVersion": "1.4.10"
18
18
  }
data/.fern/replay.lock CHANGED
@@ -30,5 +30,353 @@ generations:
30
30
  cli_version: unknown
31
31
  generator_versions:
32
32
  fernapi/fern-ruby-sdk: 1.1.13
33
- current_generation: 8487841eae05855059210650ab3ee913538f1afc
34
- patches: []
33
+ - commit_sha: c93862aca1a52c6c033c908ebab873ca9ef6e401
34
+ tree_hash: 8af2113b2953c214b34eb7360fb741106399623c
35
+ timestamp: 2026-07-14T14:45:31.832Z
36
+ cli_version: unknown
37
+ generator_versions:
38
+ fernapi/fern-ruby-sdk: 1.1.13
39
+ - commit_sha: dfe70dc9f1f1787aa5b55f6802739898633c35c7
40
+ tree_hash: 114498346f315168be50ca9bf5c9f463bcfe3303
41
+ timestamp: 2026-07-22T19:30:43.525Z
42
+ cli_version: unknown
43
+ generator_versions:
44
+ fernapi/fern-ruby-sdk: 1.1.13
45
+ current_generation: dfe70dc9f1f1787aa5b55f6802739898633c35c7
46
+ patches:
47
+ - id: patch-5da692c2
48
+ content_hash: sha256:e652287219a0a709e16112ced444e6472c6fa8bdfe888edf868caaf9769a9472
49
+ original_commit: 5da692c20aef08577d900f9a860b5f78a549418e
50
+ original_message: inject host time into datastream wasm rules engine (SCHY-471)
51
+ original_author: Christopher Brady <chris@schematichq.com>
52
+ base_generation: dfe70dc9f1f1787aa5b55f6802739898633c35c7
53
+ files:
54
+ - test/rules_engine_clock_test.rb
55
+ patch_content: |
56
+ diff --git a/test/rules_engine_clock_test.rb b/test/rules_engine_clock_test.rb
57
+ new file mode 100644
58
+ index 0000000..8711b5e
59
+ --- /dev/null
60
+ +++ b/test/rules_engine_clock_test.rb
61
+ @@ -0,0 +1,75 @@
62
+ +# frozen_string_literal: true
63
+ +
64
+ +require_relative "test_helper"
65
+ +require "minitest/autorun"
66
+ +
67
+ +# Regression for SCHY-471.
68
+ +#
69
+ +# A company-override entitlement rule whose metric condition uses a
70
+ +# calendar/billing metric period drives the engine into the metric-period-reset
71
+ +# code path, which needs a wall clock. On the raw wasm32-unknown-unknown build
72
+ +# that path used to trap (+wasm unreachable+); the flag then wrongly fell back to
73
+ +# its default value for a company that is legitimately entitled. The host now
74
+ +# injects the current time via +setCurrentTimeMillis+ so this evaluates cleanly.
75
+ +class RulesEngineClockTest < Minitest::Test
76
+ + def setup
77
+ + @engine = Schematic::RulesEngine.new
78
+ + @engine.initialize!
79
+ + # The wasm binary is fetched via scripts/download-wasm.sh and may be absent
80
+ + # (or the wasmtime gem missing) in some environments — skip rather than fail.
81
+ + skip "WASM rules engine unavailable (wasm binary or wasmtime gem missing)" unless @engine.initialized?
82
+ + end
83
+ +
84
+ + def flag
85
+ + {
86
+ + "id" => "flag1", "key" => "mcp-access", "account_id" => "acc_1",
87
+ + "environment_id" => "env_1", "default_value" => false, "rules" => []
88
+ + }
89
+ + end
90
+ +
91
+ + # Usage 40 < allocation 100, so the override grants the feature.
92
+ + def entitled_company
93
+ + {
94
+ + "id" => "co_entitled", "account_id" => "acc_1", "environment_id" => "env_1",
95
+ + "keys" => { "id" => "co_entitled" },
96
+ + "metrics" => [{
97
+ + "account_id" => "acc_1", "environment_id" => "env_1", "company_id" => "co_entitled",
98
+ + "event_subtype" => "api-calls", "period" => "current_month",
99
+ + "month_reset" => "billing_cycle", "value" => 40, "created_at" => "2023-01-01T00:00:00Z"
100
+ + }],
101
+ + "rules" => [{
102
+ + "id" => "rule_override", "flag_id" => "flag1", "account_id" => "acc_1",
103
+ + "environment_id" => "env_1", "name" => "Company Override",
104
+ + "rule_type" => "company_override", "priority" => 0, "value" => true,
105
+ + "condition_groups" => [],
106
+ + "conditions" => [
107
+ + {
108
+ + "id" => "cond_company", "account_id" => "acc_1", "environment_id" => "env_1",
109
+ + "condition_type" => "company", "operator" => "eq",
110
+ + "resource_ids" => ["co_entitled"], "trait_value" => ""
111
+ + },
112
+ + {
113
+ + "id" => "cond_metric", "account_id" => "acc_1", "environment_id" => "env_1",
114
+ + "condition_type" => "metric", "operator" => "lt", "event_subtype" => "api-calls",
115
+ + "metric_value" => 100, "metric_period" => "current_month",
116
+ + "metric_period_month_reset" => "billing_cycle", "trait_value" => "100"
117
+ + }
118
+ + ]
119
+ + }]
120
+ + }
121
+ + end
122
+ +
123
+ + def test_billing_metric_override_evaluates_without_trapping
124
+ + result = @engine.check_flag(flag, entitled_company)
125
+ +
126
+ + assert result[:value], "company override should grant the flag, not fall back to default false"
127
+ + assert_match(/override/i, result[:reason].to_s)
128
+ + end
129
+ +
130
+ + def test_billing_metric_override_populates_reset_at
131
+ + result = @engine.check_flag(flag, entitled_company)
132
+ +
133
+ + refute_nil result[:feature_usage_reset_at],
134
+ + "reset-at should be computed from the injected host time"
135
+ + end
136
+ +end
137
+ theirs_snapshot:
138
+ test/rules_engine_clock_test.rb: |
139
+ # frozen_string_literal: true
140
+
141
+ require_relative "test_helper"
142
+ require "minitest/autorun"
143
+
144
+ # Regression for SCHY-471.
145
+ #
146
+ # A company-override entitlement rule whose metric condition uses a
147
+ # calendar/billing metric period drives the engine into the metric-period-reset
148
+ # code path, which needs a wall clock. On the raw wasm32-unknown-unknown build
149
+ # that path used to trap (+wasm unreachable+); the flag then wrongly fell back to
150
+ # its default value for a company that is legitimately entitled. The host now
151
+ # injects the current time via +setCurrentTimeMillis+ so this evaluates cleanly.
152
+ class RulesEngineClockTest < Minitest::Test
153
+ def setup
154
+ @engine = Schematic::RulesEngine.new
155
+ @engine.initialize!
156
+ # The wasm binary is fetched via scripts/download-wasm.sh and may be absent
157
+ # (or the wasmtime gem missing) in some environments — skip rather than fail.
158
+ skip "WASM rules engine unavailable (wasm binary or wasmtime gem missing)" unless @engine.initialized?
159
+ end
160
+
161
+ def flag
162
+ {
163
+ "id" => "flag1", "key" => "mcp-access", "account_id" => "acc_1",
164
+ "environment_id" => "env_1", "default_value" => false, "rules" => []
165
+ }
166
+ end
167
+
168
+ # Usage 40 < allocation 100, so the override grants the feature.
169
+ def entitled_company
170
+ {
171
+ "id" => "co_entitled", "account_id" => "acc_1", "environment_id" => "env_1",
172
+ "keys" => { "id" => "co_entitled" },
173
+ "metrics" => [{
174
+ "account_id" => "acc_1", "environment_id" => "env_1", "company_id" => "co_entitled",
175
+ "event_subtype" => "api-calls", "period" => "current_month",
176
+ "month_reset" => "billing_cycle", "value" => 40, "created_at" => "2023-01-01T00:00:00Z"
177
+ }],
178
+ "rules" => [{
179
+ "id" => "rule_override", "flag_id" => "flag1", "account_id" => "acc_1",
180
+ "environment_id" => "env_1", "name" => "Company Override",
181
+ "rule_type" => "company_override", "priority" => 0, "value" => true,
182
+ "condition_groups" => [],
183
+ "conditions" => [
184
+ {
185
+ "id" => "cond_company", "account_id" => "acc_1", "environment_id" => "env_1",
186
+ "condition_type" => "company", "operator" => "eq",
187
+ "resource_ids" => ["co_entitled"], "trait_value" => ""
188
+ },
189
+ {
190
+ "id" => "cond_metric", "account_id" => "acc_1", "environment_id" => "env_1",
191
+ "condition_type" => "metric", "operator" => "lt", "event_subtype" => "api-calls",
192
+ "metric_value" => 100, "metric_period" => "current_month",
193
+ "metric_period_month_reset" => "billing_cycle", "trait_value" => "100"
194
+ }
195
+ ]
196
+ }]
197
+ }
198
+ end
199
+
200
+ def test_billing_metric_override_evaluates_without_trapping
201
+ result = @engine.check_flag(flag, entitled_company)
202
+
203
+ assert result[:value], "company override should grant the flag, not fall back to default false"
204
+ assert_match(/override/i, result[:reason].to_s)
205
+ end
206
+
207
+ def test_billing_metric_override_populates_reset_at
208
+ result = @engine.check_flag(flag, entitled_company)
209
+
210
+ refute_nil result[:feature_usage_reset_at],
211
+ "reset-at should be computed from the injected host time"
212
+ end
213
+ end
214
+ user_owned: true
215
+ - id: patch-ee61788c
216
+ content_hash: sha256:e652287219a0a709e16112ced444e6472c6fa8bdfe888edf868caaf9769a9472
217
+ original_commit: ee61788c5a83fce5dd5768b2536391459550d176
218
+ original_message: fix rubocop offenses in clock regression test (SCHY-471)
219
+ original_author: Christopher Brady <chris@schematichq.com>
220
+ base_generation: dfe70dc9f1f1787aa5b55f6802739898633c35c7
221
+ files:
222
+ - test/rules_engine_clock_test.rb
223
+ patch_content: |
224
+ diff --git a/test/rules_engine_clock_test.rb b/test/rules_engine_clock_test.rb
225
+ new file mode 100644
226
+ index 0000000..8711b5e
227
+ --- /dev/null
228
+ +++ b/test/rules_engine_clock_test.rb
229
+ @@ -0,0 +1,75 @@
230
+ +# frozen_string_literal: true
231
+ +
232
+ +require_relative "test_helper"
233
+ +require "minitest/autorun"
234
+ +
235
+ +# Regression for SCHY-471.
236
+ +#
237
+ +# A company-override entitlement rule whose metric condition uses a
238
+ +# calendar/billing metric period drives the engine into the metric-period-reset
239
+ +# code path, which needs a wall clock. On the raw wasm32-unknown-unknown build
240
+ +# that path used to trap (+wasm unreachable+); the flag then wrongly fell back to
241
+ +# its default value for a company that is legitimately entitled. The host now
242
+ +# injects the current time via +setCurrentTimeMillis+ so this evaluates cleanly.
243
+ +class RulesEngineClockTest < Minitest::Test
244
+ + def setup
245
+ + @engine = Schematic::RulesEngine.new
246
+ + @engine.initialize!
247
+ + # The wasm binary is fetched via scripts/download-wasm.sh and may be absent
248
+ + # (or the wasmtime gem missing) in some environments — skip rather than fail.
249
+ + skip "WASM rules engine unavailable (wasm binary or wasmtime gem missing)" unless @engine.initialized?
250
+ + end
251
+ +
252
+ + def flag
253
+ + {
254
+ + "id" => "flag1", "key" => "mcp-access", "account_id" => "acc_1",
255
+ + "environment_id" => "env_1", "default_value" => false, "rules" => []
256
+ + }
257
+ + end
258
+ +
259
+ + # Usage 40 < allocation 100, so the override grants the feature.
260
+ + def entitled_company
261
+ + {
262
+ + "id" => "co_entitled", "account_id" => "acc_1", "environment_id" => "env_1",
263
+ + "keys" => { "id" => "co_entitled" },
264
+ + "metrics" => [{
265
+ + "account_id" => "acc_1", "environment_id" => "env_1", "company_id" => "co_entitled",
266
+ + "event_subtype" => "api-calls", "period" => "current_month",
267
+ + "month_reset" => "billing_cycle", "value" => 40, "created_at" => "2023-01-01T00:00:00Z"
268
+ + }],
269
+ + "rules" => [{
270
+ + "id" => "rule_override", "flag_id" => "flag1", "account_id" => "acc_1",
271
+ + "environment_id" => "env_1", "name" => "Company Override",
272
+ + "rule_type" => "company_override", "priority" => 0, "value" => true,
273
+ + "condition_groups" => [],
274
+ + "conditions" => [
275
+ + {
276
+ + "id" => "cond_company", "account_id" => "acc_1", "environment_id" => "env_1",
277
+ + "condition_type" => "company", "operator" => "eq",
278
+ + "resource_ids" => ["co_entitled"], "trait_value" => ""
279
+ + },
280
+ + {
281
+ + "id" => "cond_metric", "account_id" => "acc_1", "environment_id" => "env_1",
282
+ + "condition_type" => "metric", "operator" => "lt", "event_subtype" => "api-calls",
283
+ + "metric_value" => 100, "metric_period" => "current_month",
284
+ + "metric_period_month_reset" => "billing_cycle", "trait_value" => "100"
285
+ + }
286
+ + ]
287
+ + }]
288
+ + }
289
+ + end
290
+ +
291
+ + def test_billing_metric_override_evaluates_without_trapping
292
+ + result = @engine.check_flag(flag, entitled_company)
293
+ +
294
+ + assert result[:value], "company override should grant the flag, not fall back to default false"
295
+ + assert_match(/override/i, result[:reason].to_s)
296
+ + end
297
+ +
298
+ + def test_billing_metric_override_populates_reset_at
299
+ + result = @engine.check_flag(flag, entitled_company)
300
+ +
301
+ + refute_nil result[:feature_usage_reset_at],
302
+ + "reset-at should be computed from the injected host time"
303
+ + end
304
+ +end
305
+ theirs_snapshot:
306
+ test/rules_engine_clock_test.rb: |
307
+ # frozen_string_literal: true
308
+
309
+ require_relative "test_helper"
310
+ require "minitest/autorun"
311
+
312
+ # Regression for SCHY-471.
313
+ #
314
+ # A company-override entitlement rule whose metric condition uses a
315
+ # calendar/billing metric period drives the engine into the metric-period-reset
316
+ # code path, which needs a wall clock. On the raw wasm32-unknown-unknown build
317
+ # that path used to trap (+wasm unreachable+); the flag then wrongly fell back to
318
+ # its default value for a company that is legitimately entitled. The host now
319
+ # injects the current time via +setCurrentTimeMillis+ so this evaluates cleanly.
320
+ class RulesEngineClockTest < Minitest::Test
321
+ def setup
322
+ @engine = Schematic::RulesEngine.new
323
+ @engine.initialize!
324
+ # The wasm binary is fetched via scripts/download-wasm.sh and may be absent
325
+ # (or the wasmtime gem missing) in some environments — skip rather than fail.
326
+ skip "WASM rules engine unavailable (wasm binary or wasmtime gem missing)" unless @engine.initialized?
327
+ end
328
+
329
+ def flag
330
+ {
331
+ "id" => "flag1", "key" => "mcp-access", "account_id" => "acc_1",
332
+ "environment_id" => "env_1", "default_value" => false, "rules" => []
333
+ }
334
+ end
335
+
336
+ # Usage 40 < allocation 100, so the override grants the feature.
337
+ def entitled_company
338
+ {
339
+ "id" => "co_entitled", "account_id" => "acc_1", "environment_id" => "env_1",
340
+ "keys" => { "id" => "co_entitled" },
341
+ "metrics" => [{
342
+ "account_id" => "acc_1", "environment_id" => "env_1", "company_id" => "co_entitled",
343
+ "event_subtype" => "api-calls", "period" => "current_month",
344
+ "month_reset" => "billing_cycle", "value" => 40, "created_at" => "2023-01-01T00:00:00Z"
345
+ }],
346
+ "rules" => [{
347
+ "id" => "rule_override", "flag_id" => "flag1", "account_id" => "acc_1",
348
+ "environment_id" => "env_1", "name" => "Company Override",
349
+ "rule_type" => "company_override", "priority" => 0, "value" => true,
350
+ "condition_groups" => [],
351
+ "conditions" => [
352
+ {
353
+ "id" => "cond_company", "account_id" => "acc_1", "environment_id" => "env_1",
354
+ "condition_type" => "company", "operator" => "eq",
355
+ "resource_ids" => ["co_entitled"], "trait_value" => ""
356
+ },
357
+ {
358
+ "id" => "cond_metric", "account_id" => "acc_1", "environment_id" => "env_1",
359
+ "condition_type" => "metric", "operator" => "lt", "event_subtype" => "api-calls",
360
+ "metric_value" => 100, "metric_period" => "current_month",
361
+ "metric_period_month_reset" => "billing_cycle", "trait_value" => "100"
362
+ }
363
+ ]
364
+ }]
365
+ }
366
+ end
367
+
368
+ def test_billing_metric_override_evaluates_without_trapping
369
+ result = @engine.check_flag(flag, entitled_company)
370
+
371
+ assert result[:value], "company override should grant the flag, not fall back to default false"
372
+ assert_match(/override/i, result[:reason].to_s)
373
+ end
374
+
375
+ def test_billing_metric_override_populates_reset_at
376
+ result = @engine.check_flag(flag, entitled_company)
377
+
378
+ refute_nil result[:feature_usage_reset_at],
379
+ "reset-at should be computed from the injected host time"
380
+ end
381
+ end
382
+ user_owned: true
data/WASM_VERSION CHANGED
@@ -1 +1 @@
1
- 0.4.0
1
+ 0.6.0
@@ -11,8 +11,10 @@ module Schematic
11
11
  field :currency, -> { String }, optional: false, nullable: false
12
12
  field :customer_external_id, -> { String }, optional: false, nullable: false
13
13
  field :due_date, -> { String }, optional: true, nullable: false
14
+ field :ending_balance, -> { Integer }, optional: true, nullable: false
14
15
  field :external_id, -> { String }, optional: true, nullable: false
15
16
  field :payment_method_external_id, -> { String }, optional: true, nullable: false
17
+ field :starting_balance, -> { Integer }, optional: true, nullable: false
16
18
  field :status, -> { Schematic::Types::InvoiceStatus }, optional: true, nullable: false
17
19
  field :subscription_external_id, -> { String }, optional: true, nullable: false
18
20
  field :subtotal, -> { Integer }, optional: false, nullable: false