OpenMed v1.6.0
OpenMed 1.6.0 is the privacy assurance and release-governance release.
This release turns de-identification from a single API call into a full, auditable privacy system: policy-aware pipelines, canonical span records, deterministic safety backstops, calibrated thresholds, signed audit reports, re-identification risk scoring, and release gates that fail closed when evidence is missing.
It also adds the infrastructure needed to ship model artifacts responsibly: manifest-driven model cards, Hugging Face publishing controls, dependency and secret-scanning gates, public benchmark reporting, and a richer evaluation suite.
Highlights
- Added a policy-aware de-identification runtime built around canonical
OpenMedSpanrecords, a ten-stage privacy pipeline, detector arbitration, calibrated thresholds, deterministic safety sweeps, and six bundled policy profiles. - Added signed, reproducible audit reports with span provenance, residual-risk metadata, reproducibility hashes, and optional HMAC signatures.
- Added re-identification risk reporting and adversarial re-identification benchmark mode.
- Added a leakage-first evaluation harness with synthetic golden fixtures, public/reference dataset adapters, DUA-gated stubs, SHIELD support, weak labeling, cold-start latency, and bootstrap confidence intervals.
- Added v1.6.0 release-gate infrastructure: last-green baselines, calibration artifacts, G1a-G8 signed reports, quantization recall-delta checks, status/leaderboard generation, and fail-closed CI.
- Added clinical and interoperability utilities: ConText temporality and uncertainty axes, OHDSI Athena/Usagi ingestion, a Presidio bridge, and deterministic FHIR R4 transaction/batch Bundle assembly.
- Added a cardiology zero-shot label-map domain plus cardiology keyword routing metadata for future model registration.
- Added a canonical
models.jsonlmanifest, manifest refresh workflow, manifest-driven Hugging Face model cards, and HF publishing for converted MLX/CoreML artifacts. - Added a packaged
openmedCLI surface with benchmark and calibration commands, plus a de-identification cookbook notebook and clinical NER families example. - Added governance, compliance, security, device-tier, FAQ, API reference, release-channel, status, leaderboard, and notebook documentation.
The Big Picture
OpenMed v1.6.0 is about moving from "the model found PII" to "the system can prove what happened."
The new privacy stack records normalized spans, detector provenance, policy actions, thresholds, safety-sweep findings, risk metadata, and stable hashes. That makes de-identification outputs easier to audit, reproduce, benchmark, and review before they reach clinical, operational, or demo workflows.
The same theme shows up in release engineering. Model and package releases now have stronger evidence requirements: calibrated thresholds, last-green baselines, quantization deltas, release gate reports, dependency/license checks, and secret scanning.
Privacy Pipeline
deidentify() now routes through a staged privacy pipeline.
The pipeline includes:
- Unicode normalization and offset mapping
- language/script routing
- section and document-type metadata
- deterministic PII detectors
- fast PII and clinical PHI model hooks
- detector arbitration and cascade routing
- policy action assignment
- deterministic safety sweep
- auditable result emission
Bundled policy profiles:
hipaa_safe_harborhipaa_expert_review_assistgdpr_pseudonymizationresearch_limited_datasetstrict_no_leakclinical_minimal_redaction
Example:
from openmed import deidentify
result = deidentify(
"Patient Jane Rivera, MRN 123456, was seen on 2026-06-01.",
method="replace",
policy="hipaa_safe_harbor",
keep_mapping=True,
audit=False,
)
print(result.deidentified_text)Use audit=True when you need the signed audit-report path instead of the regular DeidentificationResult.
Audit And Risk
OpenMed now includes signed audit reports and re-identification risk scoring.
Audit reports can include:
- canonical span records
- detector and policy provenance
- threshold metadata
- residual-risk summaries
- reproducibility hashes
- optional HMAC signatures
Risk reporting adds leakage and re-identification views for text and tabular records, including singleton and quasi-identifier analysis. The new adversarial re-identification benchmark mode lets release candidates be tested against round-trip and surrogate-consistency failures.
Evaluation And Release Gates
The new evaluation framework is leakage-first. It adds BenchmarkReport, golden fixtures, SHIELD comparison support, weak labeling, public/gated dataset adapters, cold-start latency, bootstrap confidence intervals, and report rendering.
Release gates now cover G1a-G8 readiness checks with signed reports and fail-closed CI. The release-gate workflow expects evidence for:
- release metadata
- calibration thresholds
- masking and replacement profiles
- G8 span fixtures
- quantization recall deltas for quantized formats
- last-green baseline comparisons
This is not only for dashboards. It is meant to prevent a model artifact from being promoted without the evidence needed to defend the release.
Clinical And Interoperability
v1.6.0 adds several clinical interoperability building blocks:
- cardiology zero-shot labels:
CardiacFinding,ECGFinding,EjectionFraction,CardiacProcedure,CardiacDevice, andAnatomy - cardiology keyword routing metadata for ECG findings, ejection fraction, arrhythmias, stents, pacemakers, murmurs, echocardiograms, and related cardiology text
- ConText temporality axis: recent, historical, hypothetical
- ConText uncertainty axis
- OHDSI Athena vocabulary loader
- Usagi mapping ingestion
- Presidio adapter
- FHIR R4 Bundle assembler
The FHIR assembler produces deterministic transaction/batch Bundles with stable urn:uuid fullUrl values, internal reference rewriting, and request metadata for server ingestion.
No cardiology model is registered in v1.6.0. Cardiology routing is forward metadata and zero-shot label-map support; public model suggestions still fall back to existing general medical recommendations until a cardiology model ships.
Model Manifest And Publishing
The canonical model manifest is now a first-class artifact.
This release adds:
models.jsonl- manifest refresh workflow
- manifest-driven model registry loading
- manifest-driven model card generation
- Hugging Face upload support for converted MLX/CoreML artifacts
- protected
hf-publishenvironment policy HF_WRITE_TOKENhandling guidance
Packaging now includes the manifest, gate baseline, policy/schema JSON, LICENSE, and NOTICE so release artifacts have the metadata they need.
CLI, Docs, And Examples
The openmed CLI is now packaged and includes benchmark and calibration commands. The benchmark command supports SHIELD suite runs, multi-model JSON output, and adversarial re-identification mode.
New and refreshed documentation includes:
- de-identification cookbook notebook
- clinical NER families example
- project FAQ
- mkdocstrings API reference
- compliance posture
- release streams and channels
- HF token policy
- dependency and secret-handling docs
- device-tier SLOs
- status and leaderboard pages
Security And CI
v1.6.0 expands release hardening:
- protected HF publish environment
- dependency license policy gate
pip-auditgate with time-boxed ignores- gitleaks CI/pre-commit secret scanning
- grouped GitHub Actions Dependabot updates
- repo policy checks
- Ruff-based Python lint/format
- Swift
swift-formatscripts and CI gate - release-gates workflow
The old duplicate .github/workflows/release.yml workflow was removed. PyPI publishing now goes through the guarded tag/manual publish.yml workflow.
Fixes
- REST/MCP PII schemas now accept
ar,ja, andtr. - Privacy-filter
trust_remote_codeallowlist matching is case-insensitive. - Feb 29 date shifting clamps safely when
keep_year=Truetargets a non-leap year. - REST requests are capped by
OPENMED_SERVICE_MAX_TEXT_LENGTHand return 422 on oversized text. BatchProcessor.iter_processnow honorsbatch_sizewhile preserving order.- Duplicate benchmark fixture IDs are rejected.
- Duplicate benchmark CLI registration was fixed.
- Release gates skip cleanly when no candidate report exists.
- User-controlled HTML formatter fields are escaped.
- Long non-ASCII/CJK clinical text is no longer rejected as suspicious content.
- Reversible
removemappings and repeated same-type placeholders now work withkeep_mapping=True.
Migration Notes
deidentify(..., audit=True)returns an audit report. Leaveaudit=Falsewhen callers expectDeidentificationResult.deidentify(..., keep_mapping=True)can now produce unique repeated placeholders such as[NAME_2]. Snapshot tests may need updates. Withoutkeep_mapping, legacy repeated mask placeholders are preserved.- Prefer
method="shift_dates"in new code.shift_datesremains available as a compatibility alias. - REST clients sending more than
OPENMED_SERVICE_MAX_TEXT_LENGTHcharacters now receive a 422 unless the limit is raised. - Full SHIELD and DUA corpora require approved or user-supplied access paths; restricted rows are not vendored.
- Use
.github/workflows/publish.ymlfor PyPI release operations. - Model publishing requires
HF_WRITE_TOKENin the protectedhf-publishenvironment. - Local Python formatting is now Ruff-based:
make format,make lint, andmake format-check. - Swift formatting uses
make format-swiftandmake lint-swift.
PR Review Summary
Reviewed range: v1.5.5..master
- Last release:
v1.5.5atadff5fe - Reviewed head:
origin/masterat3b62f2e - Merged PRs reviewed: 69
- Direct first-parent release-prep commits reviewed: 7 (
f654531,.gitignore;8f398cc,CHANGELOG.md;baad551,CHANGELOG.md;0769007,docs/swift-openmedkit.md;0190625,docs/website/index.html;0b9bdd8,openmed/__about__.py;3b62f2e,README.md) - Aggregate diff: 371 files changed, 40,102 insertions, 4,854 deletions
Major PR groups:
- Privacy/de-identification: #193, #194, #198, #208, #210, #218, #323, #341, #342, #343, #344, #345, #346, #371, #559
- Evaluation/release gates: #195, #203, #207, #338, #339, #353, #354, #357, #358, #360, #361, #369
- Clinical/interop/zero-shot: #332, #334, #347, #368, #370, #550, #551, #556
- Release/security/publishing: #186, #220, #221, #326, #331, #333, #364, #366, #367, #412, #554
- Docs/examples/website/CLI/service: #65, #187, #196, #197, #200, #201, #206, #212, #214, #219, #322, #355, #359, #362, #390, #401, #403, #404, #406
- Training/datasets/model registry: #188, #191, #348, #350
Open Items Before Tagging
- Reconcile the website language-support copy: PR #404 advertises 16-language PII support, while core/service/README/FAQ currently enumerate 12 PII languages (
en,fr,de,it,es,nl,hi,te,pt,ar,ja,tr). - Confirm the v1.6.0 release-gate candidate bundle has required metadata, calibration evidence, G8 span fixtures, and quantization evidence.
- Previously identified release blockers are now resolved by merged PRs: #554 / #529 rejects empty audit HMAC keys; #550 / #530 rejects duplicate FHIR
ResourceType/idvalues; #559 / #513 shifts default-model lowercasedatelabels by canonical label. - Decide whether #68 is required by release policy. GitPython is present in
uv.lockthrough the docs extra, not imported by runtime code. - #556 was merged and adds FHIR Bundle empty-input and dangling-reference regression coverage. Treat #553 as a useful non-blocking FHIR refactor unless its helper extraction is required for the release branch.
- Run the full project test/lint/release-gate suite before tagging if you want coverage beyond the targeted release-prep gates listed below.
Verification For This Draft
- Re-audited against current
origin/masteron 2026-06-22 after PRs #559, #554, #550, and #556 plus the direct release-prep commits through3b62f2ewere merged. The latest release tag is stillv1.5.5, reviewed head is3b62f2e, and the first-parent range contains 76 commits: 69 merged PRs plus direct release-prep commitsf654531,8f398cc,baad551,0769007,0190625,0b9bdd8, and3b62f2e. - Four parallel subsystem reviews were completed: privacy/de-identification, evaluation/release gates, docs/CLI/service, and CI/release/MLX.
- The pasted GitHub release-note list, live
gh pr listmetadata, and this draft resolved to the same 64 merged PR numbers before PR #551. After PR #551, #559, #554, #550, and #556, live GitHub metadata and this draft resolve to the same 69 merged PR numbers, with no missing or extra PRs. - A changed-area coverage check confirmed explicit release-note coverage for the privacy pipeline, evaluation harness, release gates, datasets, clinical interop, model manifest/publishing, CLI/service, docs/examples, website, security/CI, Swift/MLX, tests, packaging, and the direct
.gitignorecommit. - PR #551 was reviewed separately: CI passed, focused cardiology label/routing tests passed locally, Ruff passed on changed files, and the runtime probe confirmed
cardiologyzero-shot labels plus private cardiology routing while public model suggestions retain the intended fallback behavior. - PRs #559, #554, #550, and #556 were reviewed separately with parallel focused checks.
method="shift_dates"now uses canonical date labels, de-identification audit signing rejects empty HMAC keys, FHIR Bundle assembly rejects duplicateResourceType/idvalues, and empty/dangling FHIR Bundle edge cases now have regression coverage. - Latest
origin/masterCI for3b62f2epassed. python3 scripts/release/check_release_version.py --version 1.6.0passed after the local version bump.uv run --extra docs mkdocs build --strictpassed.uv run --extra dev ruff check .passed.uv run --extra dev pytest tests/unit -qpassed: 1,615 passed, 1 skipped.uv run --with build python -m buildpassed and produced 1.6.0 artifacts.uv run --with twine twine check dist/*passed.git diff --checkpassed after the changelog, version, and release-note edits.
What's Changed
- docs: on-device iOS showcase + MLX/batch performance visuals by @maziyarpanahi in #65
- Generate canonical model manifest by @maziyarpanahi in #191
- Scaffold section 4.2 package shells by @maziyarpanahi in #188
- Track CLI and MCP packages in git by @maziyarpanahi in #187
- Scaffold the openmed/eval benchmark harness with leakage-first metrics by @maziyarpanahi in #195
- Website: responsive mobile nav, 6M+ downloads stat, contribute CTA by @maziyarpanahi in #206
- Add the deterministic post-ML safety sweep recall backstop by @maziyarpanahi in #193
- Add re-identification risk scoring (risk_report) for text and tables by @maziyarpanahi in #194
- Commit synthetic golden de-identification fixtures for the eval suites by @maziyarpanahi in #203
- Add 6M+ PyPI downloads stat and contribute call-to-action by @maziyarpanahi in #212
- Add favicon, touch icon, and logo.svg for the website by @maziyarpanahi in #214
- Fix case-sensitive trust_remote_code allowlist matching by @sawirricardo in #208
- fix: accept ar/ja/tr in REST/MCP PII lang schema by @guhyun9454 in #210
- docs: complete Hindi README to parity with README.md by @Technolity in #196
- docs: fix non-functional analyze_text example in getting-started by @Technolity in #197
- fix: clamp Feb 29 when keep_year date shifting hits a leap day by @Technolity in #198
- fix: cap request text length in the REST service by @Technolity in #200
- fix: respect batch_size in BatchProcessor.iter_process by @Technolity in #201
- Consolidate PyPI publish into a single tag-triggered release workflow by @maziyarpanahi in #186
- Provision write token and CI rotation policy by @maziyarpanahi in #220
- Add HF push_to_hub publishing to the model conversion pipeline by @maziyarpanahi in #333
- Add the last-green baseline store and reproducibility hash by @maziyarpanahi in #338
- Extend label policy metadata and HIPAA cross-map by @maziyarpanahi in #323
- Define the canonical OpenMedSpan record and ship versioned JSON schemas by @maziyarpanahi in #342
- Build the staged privacy detection pipeline runtime by @maziyarpanahi in #343
- Implement detector arbitration with the cascade router and score calibration by @maziyarpanahi in #344
- Add the versioned per-label/language/policy thresholds matrix by @maziyarpanahi in #345
- Implement the six policy profiles and the deidentify(policy=) and REST selector by @maziyarpanahi in #346
- Author the standardized training recipe package with three presets by @maziyarpanahi in #348
- Add cold_start_ms measurement to the eval harness by @handlecusion in #353
- Add project FAQ page by @Vishnupriyaaaaaaaaaaaa in #322
- add clinical NER families example by @alberthammerich in #355
- Build signed reproducible audit report with span provenance by @maziyarpanahi in #326
- Promote quality_gates span overlap detection to deterministic resolution by @maziyarpanahi in #218
- Fit per-(model,label,language) calibration thresholds by @maziyarpanahi in #357
- Implement the ReleaseGate harness scoring G1a-G8 with a signed gate report by @maziyarpanahi in #360
- Add mkdocstrings API reference generation by @yuvrajsingh2428 in #362
- Add dependency audit gate by @alberthammerich in #364
- Add a CI secret-scanning gate to block committed credentials by @maziyarpanahi in #367
- build(deps): bump the github-actions group with 10 updates by @dependabot[bot] in #366
- reject duplicate fixture IDs by @alberthammerich in #354
- feat: generate model cards from the manifest at publish time by @pardeep-singh in #219
- Add NOTICE, governance docs, and license policy gate by @maziyarpanahi in #221
- Compute the SemVer bump and changelog from conventional commits by @maziyarpanahi in #331
- Sub-type ID_NUM for per-identifier training signal by @maziyarpanahi in #341
- Add the adversarial re-identification eval by @maziyarpanahi in #358
- Build the status page and leaderboard from the manifest and BenchmarkReport by @maziyarpanahi in #339
- Document the device-tier SLO table and compliance posture by @maziyarpanahi in #359
- Add the temporality axis (recent / historical / hypothetical) by @cycsmail in #368
- Add OHDSI Athena vocabulary loader and Usagi mapping ingestion by @annamalai2912 in #332
- Add uncertainty axis to ConText engine by @amrit110 in #334
- Add a FHIR transaction Bundle assembler with internal references by @cycsmail in #370
- Add bootstrap confidence intervals to benchmark metrics by @cycsmail in #369
- fix: use unique placeholders for repeated entity types in deidentify() (closes #222) by @rtmalikian in #371
- Scaffold the interop adapter contract and Presidio adapter by @maziyarpanahi in #347
- Wire release gates into CI fail-closed with scored quality_gates and quant-delta by @maziyarpanahi in #361
- Add public and gated dataset adapters with weak labeling by @maziyarpanahi in #350
- Add the SHIELD public comparison corpus loader and first clinical-PHI baseline by @maziyarpanahi in #207
- fix: remove duplicate _add_benchmark_command call in CLI parser (Fixes #389) by @rtmalikian in #390
- fix: roll up contributor validation, HTML, and release gate fixes by @maziyarpanahi in #403
- Update website: refreshed design, products section, 16-language support by @maziyarpanahi in #404
- Remove tracked ignored planning files by @maziyarpanahi in #406
- docs: add a de-identification cookbook notebook with end-to-end recipes by @pardeep-singh in #401
- standardize lint and formatting by @maziyarpanahi in #412
- feat: add cardiology domain to NER catalog and zero-shot label maps by @pardeep-singh in #551
- fix: shift dates for the default model by matching the canonical label by @ardittirana in #559
- fix: reject empty HMAC keys in audit sign/verify by @muhamedfazalps in #554
- fix: reject duplicate FHIR resource ids by @gaoflow in #550
- test(fhir): add regression tests for empty and dangling-reference Bundle edges by @axelray-dev in #556
New Contributors
- @sawirricardo made their first contribution in #208
- @guhyun9454 made their first contribution in #210
- @Technolity made their first contribution in #196
- @handlecusion made their first contribution in #353
- @Vishnupriyaaaaaaaaaaaa made their first contribution in #322
- @alberthammerich made their first contribution in #355
- @yuvrajsingh2428 made their first contribution in #362
- @dependabot[bot] made their first contribution in #366
- @cycsmail made their first contribution in #368
- @annamalai2912 made their first contribution in #332
- @amrit110 made their first contribution in #334
- @rtmalikian made their first contribution in #371
- @pardeep-singh made their first contribution in #551
- @ardittirana made their first contribution in #559
- @muhamedfazalps made their first contribution in #554
- @gaoflow made their first contribution in #550
- @axelray-dev made their first contribution in #556
Full Changelog: v1.5.5...v1.6.0