From 4acc10749656e507e8213cd5f50dcebdd4b56eee Mon Sep 17 00:00:00 2001 From: Stephen Romano Date: Thu, 5 Nov 2026 07:10:39 -0500 Subject: [PATCH] fix: accept metadata without retired capacity fields --- README.md | 6 ++++-- src/morphiq_sdk/models.py | 7 ++++--- tests/test_pricing.py | 13 +++++++++++++ 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 918da90..2d1aa34 100644 --- a/README.md +++ b/README.md @@ -188,8 +188,10 @@ no real credentials; native API integration is opt-in. See [CONTRIBUTING.md](https://github.com/MorphIQ-Labs/morphiq-sdk-python/blob/main/CONTRIBUTING.md) and [RELEASE.md](https://github.com/MorphIQ-Labs/morphiq-sdk-python/blob/main/RELEASE.md). Clients make no automatic retries and do not follow redirects. A timeout -may leave work charged. Missing `fcu_charged` means unreported, not zero; internal -`units_charged` is not a commercial CU charge. +may leave work charged. Only `fcu_quoted` and `fcu_charged` report commercial CUs. +Missing `fcu_charged` means unreported, not zero. The retired `units_charged` and +`compute_schedule_version` fields are optional; they remain accepted from older +deployments and are never used to calculate a charge. The SDK preserves server results, numerical diagnostics, request IDs, engine provenance and commercial Compute Units (CU). Numerical engines, model selection, diff --git a/src/morphiq_sdk/models.py b/src/morphiq_sdk/models.py index eac4798..3ea90a3 100644 --- a/src/morphiq_sdk/models.py +++ b/src/morphiq_sdk/models.py @@ -229,7 +229,8 @@ class _CommercialMetadata(_Response): class ResponseMetadata(_CommercialMetadata): """Server provenance and optional commercial CU evidence. - ``units_charged`` is an internal compute weight, not a commercial CU charge. + Only ``fcu_quoted`` and ``fcu_charged`` are commercial CU evidence. + Retired capacity fields are optional for compatibility with older deployments. Missing ``fcu_charged`` means unreported, not zero. """ @@ -237,8 +238,8 @@ class ResponseMetadata(_CommercialMetadata): api_version: str engine_version: str engines: list[EngineIdentity] - units_charged: int = Field(ge=0) - compute_schedule_version: str + units_charged: int | None = Field(default=None, ge=0, deprecated=True) + compute_schedule_version: str | None = Field(default=None, deprecated=True) class ServiceErrorMetadata(_CommercialMetadata): diff --git a/tests/test_pricing.py b/tests/test_pricing.py index 5c493be..c7b220b 100644 --- a/tests/test_pricing.py +++ b/tests/test_pricing.py @@ -460,3 +460,16 @@ async def aclose(self): assert transport.closed asyncio.run(run()) + + +@pytest.mark.parametrize("mode", ["sync", "async"]) +def test_retired_capacity_fields_are_not_required_or_used_as_cu(mode, cases): + body = copy.deepcopy(cases[0]["response"]) + body["metadata"].pop("units_charged") + body["metadata"].pop("compute_schedule_version") + body["metadata"].update(fcu_quoted=50, fcu_charged=50) + result = invoke(mode, httpx.MockTransport(lambda _: httpx.Response(200, json=body))) + assert result.metadata.fcu_quoted == 50 + assert result.metadata.fcu_charged == 50 + assert result.model_dump()["metadata"]["units_charged"] is None + assert result.model_dump()["metadata"]["compute_schedule_version"] is None