Fixed OpenPHI-Vision fixtures¶
openmed.eval.openphi_vision_fixtures loads six hand-specified synthetic cases from the bundled openphi-vision-v1 catalog. Loading and rendering are offline; Pillow is required only when loading or accessing images. The catalog supplies evaluation inputs and gold annotations for OpenPHI-Vision (#3205). It adds no scoring, release gate, model qualification, clinical validation, configurable generator, random seed API or training export.
These fixtures are non-diagnostic synthetic test inputs. They do not authorize clinical decisions or replace explicit reviewer confirmation for consequential outputs in a consuming workflow. No providers, model weights, restricted data, real patient records or cloud fallback are included.
Catalog coverage¶
| Case | Track | Fixed layout |
|---|---|---|
vision-v1-001 | documents | Identifiers in header and footer, date in body |
vision-v1-002 | documents | Footer identifiers, header date |
vision-v1-003 | documents | Header name marker and aligned form fields |
vision-v1-004 | slide_labels | Name marker, printed accession and specimen codes |
vision-v1-005 | mixed_script | Latin and Cyrillic markers in separated regions |
vision-v1-006 | packets | Four interleaved pages from two synthetic subjects |
Slide codes are printed synthetic text, not barcode/QR decoding fixtures. The catalog does not cover every script, OCR conflict, DICOM overlay, real document format or attack required by #3205. It complements the existing synthetic DICOM suite; general document and overlay generators remain in #2848 and #2849. This issue is scoped to the Python evaluation catalog, not a new OpenMedKit runtime API. The in-memory PGM bytes can also serve as shared image inputs for downstream platform tests without changing their pixel contract.
Loader and gold contract¶
from openmed.eval.openphi_vision_fixtures import load_openphi_vision_fixtures
cases = tuple(load_openphi_vision_fixtures())
case = cases[0]
page = case.pages[0]
image = page.to_image() # Detached grayscale Pillow image for a local provider.
gold = page.gold_boxes # Keep local; do not include values in evidence.
assert case.version == "openphi-vision-v1"
assert case.expected_packet_splits == ((0,),)
Cases, pages and gold boxes are frozen objects. Page text, gold text and PGM bytes are omitted from every nested repr; explicit .text access remains available for local span checks. Identifiers and names in the source catalog are obvious synthetic markers. Case/page IDs are opaque controlled codes.
Each gold box has a canonical PERSON, ID_NUM or DATE label, a critical flag, a region code, half-open (x0, y0, x1, y1) ink bounds and [start, end) character offsets into the page's newline-joined text. Every page and track has critical direct identifiers. Dates are deliberately noncritical controls; consumer gates must assess critical leakage independently of aggregate scores.
expected_packet_splits is a tuple of groups of zero-based page indices. The packet's gold is ((0, 2), (1, 3)): grouping consecutive pages would mix subjects. Each group retains its original page order and all pages appear exactly once. This is gold membership, not an implementation of packet splitting.
Consumption by #3205¶
The suite can iterate cases, send only page.to_image() to an offline OCR or vision provider, and compare its returned local annotations against the gold. It must retain page_id, coordinates and offsets, evaluate each critical box, and compare packet membership without crossing the gold patient boundaries. The suite owns label matching, OCR conflict handling, leakage scoring, thresholds, review requirements and release evidence; no proposed suite API is assumed here.
Safe diagnostics can include case_id, page_id, version, track, counts, box coordinates, offsets and SHA-256 digests. Do not serialize dataclasses with asdict, log explicit .text, or emit images/source declarations into audit reports: hiding values in repr is not a general serialization sanitizer.
Example metadata-only summary:
summary = {
"case_id": case.case_id,
"version": case.version,
"sha256": case.sha256,
"page_count": len(case.pages),
"critical_count": sum(box.critical for p in case.pages for box in p.gold_boxes),
}
assert summary["case_id"] == "vision-v1-001"
assert summary["page_count"] == 1
assert summary["critical_count"] == 3
Reproducibility and drift¶
The catalog, font, case declarations and every page have pinned SHA-256 digests. Case digests bind the complete declaration, including gold values, boxes, flags, layout and packet splits. Page digests cover binary PGM: the exact ASCII header P5\nWIDTH HEIGHT\n255\n followed by grayscale bytes in row order. There is no PNG compression, timestamp, EXIF, private path or model output in these bytes.
Rendering reuses the existing burned-in font-fitting and raster-measurement helpers with the bundled IBM Plex Mono Regular face (OFL-1.1, copied unchanged from the repository's font assets with its license). Pillow's BASIC layout engine avoids optional shaping and system-font fallbacks. The loader rejects drift, including differing rasterizer output, with value-free errors; it never silently repins or qualifies a different environment. A changed corpus requires a reviewed version change and independently measured pins.
Focused checks:
.venv/bin/python -m pytest tests/unit/eval/test_openphi_vision_fixtures.py \
tests/integration/test_openphi_vision_fixtures.py -q
Tests independently bound rendered ink and spans, regenerate all pages, check critical flags and both scripts, verify packet membership and hidden values, and reject corrupted digests/boxes. Model-free integration controls mask every gold box, then deliberately omit a critical identifier to demonstrate residual ink. They exercise fixture consumption and do not claim provider recall or clinical safety.