diff --git a/EvoScientist/model_registry/http_api.py b/EvoScientist/model_registry/http_api.py index 758390d..41a844d 100644 --- a/EvoScientist/model_registry/http_api.py +++ b/EvoScientist/model_registry/http_api.py @@ -109,9 +109,13 @@ class GetModelRegistryResponse(BaseModel): class PutModelRegistryRequest(BaseModel): - """The section 9.2 registry save request.""" + """The section 9.2 registry save request. - expected_revision: PositiveInt + ``expected_revision`` is deprecated: accepted for backward + compatibility but ignored — saves are last-write-wins. + """ + + expected_revision: PositiveInt | None = None registry: RegistryV4 credential_writes: list[CredentialWrite] = Field(default_factory=list) diff --git a/EvoScientist/model_registry/openapi.json b/EvoScientist/model_registry/openapi.json index c20c699..e6b858f 100644 --- a/EvoScientist/model_registry/openapi.json +++ b/EvoScientist/model_registry/openapi.json @@ -1010,7 +1010,7 @@ "type": "object" }, "PutModelRegistryRequest": { - "description": "The section 9.2 registry save request.", + "description": "The section 9.2 registry save request.\n\n``expected_revision`` is deprecated: accepted for backward\ncompatibility but ignored \u2014 saves are last-write-wins.", "properties": { "credential_writes": { "items": { @@ -1020,16 +1020,23 @@ "type": "array" }, "expected_revision": { - "exclusiveMinimum": 0, - "title": "Expected Revision", - "type": "integer" + "anyOf": [ + { + "exclusiveMinimum": 0, + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Expected Revision" }, "registry": { "$ref": "#/components/schemas/RegistryV4" } }, "required": [ - "expected_revision", "registry" ], "title": "PutModelRegistryRequest", diff --git a/tests/test_model_registry_http.py b/tests/test_model_registry_http.py index d4b9deb..1d01186 100644 --- a/tests/test_model_registry_http.py +++ b/tests/test_model_registry_http.py @@ -355,13 +355,22 @@ def test_put_registry_success_returns_full_response(active_client): assert states["glm-5.2"]["state"] == "enabled" -def test_put_registry_revision_conflict(active_client): +def test_put_registry_stale_revision_is_ignored(active_client): current = _current_registry(active_client) response = _put(active_client, current["registry"], expected_revision=99) - assert response.status_code == 409 + assert response.status_code == 200 body = response.json() - assert body["code"] == "REGISTRY_REVISION_CONFLICT" - assert set(body) == {"code", "message", "details", "request_id"} + assert body["revision"] == current["revision"] + 1 + + +def test_put_registry_without_expected_revision(active_client): + current = _current_registry(active_client) + payload = {"registry": current["registry"], "credential_writes": []} + response = active_client.put( + "/api/model-registry", headers=_admin_headers(), json=payload + ) + assert response.status_code == 200 + assert response.json()["revision"] == current["revision"] + 1 def test_put_registry_rejects_ssrf_endpoint(active_client):