marginfuse 0.2.0 → 0.3.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ed4b052cde767f31778131e10df10f850d206c4db7f2215040de98faec393af0
4
- data.tar.gz: 428cb94a4937c73876d998db48026aea9b2f8b69730b1149bd5e3947051a19c9
3
+ metadata.gz: c0b1ac060efeb37a1cff83a21bfec10f5e5972c67622a637100b00746a9defbe
4
+ data.tar.gz: '0058b2089e6d46488e0db908ad66e675f83e1b4a8116abdb2edef4a557e7445f'
5
5
  SHA512:
6
- metadata.gz: e7d968bfd7aa9d82acaa132b72402396cca466b6940d825da506326b7a508376dcbacf203cc16529a7f8d98c0a52f9e3b6d04ba3341820ca1eea8541b0443bb5
7
- data.tar.gz: 2cd18e81de9e717d56607177da46c46c758bb46a443c9bebe2298e16ad68873156bd1e5123d3b09c24460f68823d53ec7064d942be43da0938d52e07fa2b1a5e
6
+ metadata.gz: 79059326eec63bb75f28c62b93d144d236d14450d477100be60423b7a6a655dfba9556277f9452ae55f204b8c90e60bb43fcc9008fe3bfedc5b4dbf8f0c334a8
7
+ data.tar.gz: 0f8bea6add4ee66ac6badb04073b362b08f1ab22524479407b9cd1b475b7d2f152e69d020a41c712eadef3dcf5fd667bc82ce005edb8e39b3682bc4f7734ceb9
data/CHANGELOG.md CHANGED
@@ -4,6 +4,28 @@ All notable changes to this project are documented here. The format follows
4
4
  [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and this project
5
5
  follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [0.3.0]
8
+
9
+ ### Fixed
10
+
11
+ - A downgrade that crosses vendors is reported against the vendor that actually
12
+ ran it. `guard()` already ran the model the server chose, but the usage event
13
+ still named the requested provider, so the call was priced from the wrong
14
+ catalog and the saving the downgrade exists to prove was computed against the
15
+ wrong basis. An `allow` is unchanged, because the decision already defaults
16
+ its provider to the requested one.
17
+ - A downgrade whose provider call then fails is acknowledged as
18
+ `used_downgrade_model` rather than `proceeded_as_requested`. The cheaper model
19
+ did run; what failed came after. Reporting otherwise told reconciliation the
20
+ policy never applied, which skewed realized-savings attribution on the error
21
+ path.
22
+
23
+ ### Changed
24
+
25
+ - Pinned contract v2, whose new scenarios cover both corrections above and add
26
+ a privacy check that hands the SDK content-bearing fields and scans the bytes
27
+ that actually leave the process.
28
+
7
29
  ## [0.2.0]
8
30
 
9
31
  ### Added
@@ -208,7 +208,8 @@ module MarginFuse
208
208
  #
209
209
  # Yields the decision to the block, which must return a hash with +:usage+
210
210
  # and optionally +:result+, +:cost_usd+ and +:outcome+. Use
211
- # +decision.model+: a downgrade verdict changes it.
211
+ # +decision.model+ and +decision.provider+: a downgrade verdict changes
212
+ # them, and it can send you to another vendor.
212
213
  #
213
214
  # It yields rather than returning a decision for you to act on, because
214
215
  # enforcement must not depend on the caller remembering to check anything.
@@ -234,27 +235,34 @@ module MarginFuse
234
235
  return GuardOutcome.new(kind: :topup_required, decision: decision)
235
236
  end
236
237
 
238
+ # A downgrade can cross vendors, so the vendor that ran the call comes
239
+ # from the decision exactly as the model does. Reporting the caller's
240
+ # would price the call from the wrong catalog and credit the saving to the
241
+ # wrong vendor. The decision defaults both to what was asked for, so
242
+ # anything but a downgrade reports what it always did.
237
243
  model_used = decision.action == :downgrade ? decision.model : model
244
+ provider_used = decision.action == :downgrade ? decision.provider : provider
245
+ # A downgrade whose provider call then fails is still a downgrade: the
246
+ # cheaper model is the one that ran, so both paths acknowledge the same.
247
+ acknowledgment =
248
+ decision.action == :downgrade ? :used_downgrade_model : :proceeded_as_requested
238
249
 
239
250
  begin
240
251
  call = yield(decision)
241
252
  rescue Exception => e # rubocop:disable Lint/RescueException
242
- track(customer_id: customer_id, plan: plan, feature: feature, provider: provider,
253
+ track(customer_id: customer_id, plan: plan, feature: feature, provider: provider_used,
243
254
  model: model_used, requested_model: model, usage: {},
244
255
  outcome: :provider_error, decision_id: decision.id)
245
- acknowledge(decision.id, :proceeded_as_requested) if decision.id
256
+ acknowledge(decision.id, acknowledgment) if decision.id
246
257
  raise e
247
258
  end
248
259
 
249
260
  call ||= {}
250
- track(customer_id: customer_id, plan: plan, feature: feature, provider: provider,
261
+ track(customer_id: customer_id, plan: plan, feature: feature, provider: provider_used,
251
262
  model: model_used, requested_model: model, usage: call[:usage],
252
263
  cost_usd: call[:cost_usd], outcome: call[:outcome] || :success,
253
264
  decision_id: decision.id)
254
- if decision.id
255
- acknowledge(decision.id,
256
- decision.action == :downgrade ? :used_downgrade_model : :proceeded_as_requested)
257
- end
265
+ acknowledge(decision.id, acknowledgment) if decision.id
258
266
 
259
267
  GuardOutcome.new(kind: :completed, decision: decision, result: call[:result])
260
268
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MarginFuse
4
- VERSION = "0.2.0"
4
+ VERSION = "0.3.0"
5
5
 
6
6
  # The version of the shared SDK contract this build was verified against.
7
7
  #
@@ -12,5 +12,5 @@ module MarginFuse
12
12
  # same vectors.
13
13
  #
14
14
  # See github.com/marginfuse/sdk-contract
15
- CONTRACT_VERSION = 1
15
+ CONTRACT_VERSION = 2
16
16
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: marginfuse
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pemira Labs
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-09-03 00:00:00.000000000 Z
11
+ date: 2026-09-04 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: |-
14
14
  MarginFuse server-side SDK. Connect revenue to per-request AI cost, see gross