Skip to content

Migrate from OpenMed 2.3 to 2.5

The baseline for this minor release is v2.3.0. No stable v2.4.0 tag intervenes. Compare the exact candidate before tagging:

python scripts/release/api_surface_diff.py v2.3.0 HEAD \
  --json api-surface-diff.json \
  --check docs/migration/2.3-to-2.5.md

Use WORKTREE instead of HEAD while reviewing uncommitted preparation. The static inventory does not evaluate return-value semantics, serialized schemas, CLI flags, model labels, or native platform behavior.

Compatibility result

The static Python surface grows from 41,729 to 48,178 symbols, with 6,449 additions, zero breaking changes, and zero newly deprecated symbols. The original family-based registry API and CLI are retained.

Registry APIs and persisted state

Existing v2.3 callers continue using the same class and keyword names:

from openmed.core.registry_service import RegistryService

service = RegistryService(manifest_path="models.jsonl", state_path="registry.json")
service.pointers(family="PII")
service.lineage(family="PII")
service.flip_pointer(family="PII", name="canary", target=repo_id, gate_report=gate)
service.rollback(family="PII", gate_report=last_green_gate)

Existing schema-v1 files retain their families, versions, and family-keyed return values. Loading the committed schema-v2 state through the family API produces a legacy view when each family has exactly one slot. Reads do not rewrite the file; subsequent writes retain schema v2 and use its coordinate checks. Legacy view versions retain the v2.3 display-version contract. registry list --family PII, family lineage and rollback selectors, and unambiguous family model aliases remain available.

Applications adopting multiple tier/format channels explicitly select the additive slot service and its stored assigned versions:

from openmed.core.registry_service import SlotRegistryService

service = SlotRegistryService(manifest_path="models.jsonl", state_path="slots.json")
service.pointers(slot="pii::small::mlx-fp")
service.lineage(slot="pii::small::mlx-fp")

The slot implementation and schema-v2 helpers live in openmed.core.registry_slots. Slot state uses schema_version: 2, slots keyed by family::tier::format, and checkpoints with assigned versions. These assigned versions must not be inferred from a repository-name suffix. The family adapter refuses ambiguous multi-slot families without writing. Use the explicit slot API before creating a second channel for one family.

Administrators who choose to migrate a caller-owned v1 file can inspect:

python scripts/release/registry_ctl.py migrate --help

Migration requires local manifest and baseline coordinate evidence and refuses missing, ambiguous, or cross-slot pointers without changing the file. Existing v1 applications do not need to run it to upgrade the SDK. The committed representation migration retains every model target and all canary, latest, and last_green target values.

Clinical processing and privacy

Existing default privacy paths remain the starting point. Clinical-preserving processing is an explicit preview policy with language/category/role controls, per-document review status, and source-offset evidence. Requalify direct identifier recall, critical leakage, span integrity, date handling, surrogate consistency, and clinical-text preservation for each deployed language and quantized runtime. German regression coverage is not a multilingual qualification claim.

Context, medication quantities, measurement relations, and temporal events remain source-backed assistive evidence. Handle abstentions and withheld ambiguous quantities; do not derive clinical decisions from test coverage.

REST, CLI, and serialized records

The main REST specification adds Persian to the language enum. Existing paths and component schemas are retained. Generated TypeScript and Go clients expose the corresponding language value.

The privacy-proxy application is separate and requires an injected transport. Unconfigured requests fail locally. Placeholder mappings are request-scoped; responses with unknown or malformed placeholders are rejected. Account for its added stable error categories when adopting that application.

Run summaries, provider results, governance identifiers, audit envelopes, federated updates, and artifact references use strict bounded schemas. Use their parser and serializer APIs; reject unknown fields, non-finite numbers, unsupported schema versions, and free-text metadata. Refresh local schema snapshots only for the new contracts your application adopts.

Multimodal and structured data

Asset preflight adds bounded BMP/GIF/WebP headers, WAV metadata, explicit pre-decode limit profiles, and an accept-or-abstain report. Keep byte, pixel, page, frame, duration, and digest limits finite. An unsupported or unevaluable check is an abstention. Memory-streamed OCR still requires a caller-installed Tesseract binary; PDF raster operations require their optional runtime.

FHIR and OMOP validators are structural and provenance checks, not a clinical correctness guarantee. Keep licensed vocabularies and the official Java FHIR validator out of bundled artifacts. ValueSet endpoint delegation, the terminology cache, and Snowpark are opt-in integrations with caller-owned configuration.

Platforms and release operations

Swift, Android, and npm install coordinates move to 2.5.0. Their runtime APIs are reviewed separately from Python; the new Python clinical/governance APIs do not imply native platform parity. Exercise enabled adapters on the actual deployment device.

Update container and Helm image selectors together. Keep SDK publication separate from model promotion, retraining execution, warehouse processing, trace deletion, upload guards, and other explicit local or external actions.