Skip to content

Update spec for 0.9.dev1 including RFCs 3 & 4 - #190

Merged
joshmoore merged 12 commits into
ome:0.9devfrom
jni:0.9dev1
Aug 25, 2026
Merged

Update spec for 0.9.dev1 including RFCs 3 & 4#190
joshmoore merged 12 commits into
ome:0.9devfrom
jni:0.9dev1

Conversation

@jni

@jni jni commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

0.9.dev1 is intended to be:

in current WIP this only includes RFC3. I need to get RFC4 in before we merge this.

Edit 1 (2026-08-20): updated title to 0.9.dev1 to reflect discussion and match PEP-440.

Edit 2 (2026-08-21): This PR now contains all of the listed requirements (RFC3, RFC4, #87 omero fields optional) and should be ready to merge to allow implementations to start to be written against it. Some notes below.

notes

The limits removals on coordinate-transformations are the thing I'm least sure about, would appreciate extra eyes there.

In schemas/coordinate_transformations.schema, rotation is defined by a 2, 3, 4, or 5-dimensional rotation matrix. This is incompatible with RFC-3 but cannot be easily extended to an arbitrary number of dimensions.

Possible solutions:

  • Amend RFC-3 to have a large number of max dimensions (say, 12? 16?), and continue the definition given the arbitrary rotations
  • For higher-dimensional rotations, allow instead a sequence of 2-axis rotations, which compose into a high-dimensional rotation. (Can higher-dimensional rotations always be decomposed in this way?)
  • Amend 0.6/RFC-5 to disallow >3D rotations, since they are very uncommon, and can already be decomposed (as a sequence of 2D rotations, because sequences are already a thing.)

I'm also not sure about 6199f0e and the difference to 93c1ba7.

Finally I don't know how to express that orientation can only be present if axis type is "space".

@github-actions

Copy link
Copy Markdown

Automated Review URLs

@sbesson

sbesson commented Aug 19, 2026

Copy link
Copy Markdown
Member

@jni thanks for starting this work. We're looking forward to having a first rendered version of this specification as well as dev schemas that we can use to validate datasets generated by implementations!

Immediate question: is the next version number 0.9dev1 (as in this PR) or 0.9.dev1 (used in a few public discussions)?

We have no opinion one way or the other, but we have used the latter so far so if the consensus is to move towards the first form, we will need to update our implementation and regenerate sample data /cc @melissalinkert

@clbarnes

clbarnes commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

is the next version number 0.9dev1 (as in this PR) or 0.9.dev1 (used in a few public discussions)

This came up with the dev versions in 0.6. Because we use python tooling in the build step of the repo, we normalised on PEP440-style version specifiers 0.6.dev0 and 0.6rc0. Overfitting to the language we happen to be using for the build is not ideal, but it's pretty well specified with implementations in many languages, while allowing a lot of flexibility in the information included in a version string. The inconsistency in . between the dev and a/b/rc is annoying, but I suppose it's intended so that you can have a dev version for an alpha release, and so on. This rust crate has a good run-down of the downsides of PEP440.

Standard SemVer would use something like 0.9-dev.1 but, other than .-delimiting, treats string and numeric components of the pre-release version as arbitrary, to be sorted lexicographically and numerically respectively. e.g. dev would come after alpha and beta. It also doesn't allow post-releases (probably fine, a post-release should probably be a patch release) or epochs e.g. if we decided we wanted to switch to calver later (also probably fine).

IMO we should stick with PEP440 (0.9.dev1), or switch to standard SemVer (0.9-dev.1) and separate the versioning of the project from the versioning of the python tooling used to build it, but I don't care too much about which.

@melissalinkert

Copy link
Copy Markdown
Member

Just to be clear, then, is the use of 0.9dev1 now fully decided? I need to update glencoesoftware/bioformats2raw#330 and glencoesoftware/raw2ometiff#156 with the agreed-upon version number before merging and tagging release candidates, which we expect to do within the next few days. If the version number is still being discussed, I need to know so that merging/tagging can be delayed until the discussion is resolved.

@jni

jni commented Aug 20, 2026

Copy link
Copy Markdown
Contributor Author

Apologies, for the confusion, my confusion indeed stemmed from the inconsistency between 0.6.devN and 0.6rcN noted by @clbarnes above. I think consistency with the 0.6 series makes sense, which means I'll update this PR to match that. In short @melissalinkert @sbesson, let's go with 0.9.dev1, no need to change your outputs, I will update this PR accordingly.

@jni jni changed the title WIP: 0.9dev1 WIP: 0.9.dev1 Aug 20, 2026
@jni

jni commented Aug 20, 2026

Copy link
Copy Markdown
Contributor Author

Here's the current validation test failures:

FAILED tests/test_attributes.py::test_attributes[spec/invalid/image/missing_space_axes] - Failed: DID NOT RAISE ValidationError
FAILED tests/test_attributes.py::test_attributes[spec/invalid/image/non_existent_orientation] - Failed: DID NOT RAISE ValidationError
FAILED tests/test_attributes.py::test_attributes[spec/invalid/image/non_existent_orientation_type] - Failed: DID NOT RAISE ValidationError
FAILED tests/test_attributes.py::test_attributes[spec/invalid/transforms/bad_projectAxis_insert_too_high_dim] - Failed: DID NOT RAISE ValidationError
FAILED tests/test_attributes.py::test_attributes[spec/invalid/transforms/bad_projectAxis_insert_too_many] - Failed: DID NOT RAISE ValidationError
FAILED tests/test_attributes.py::test_attributes[spec/invalid/transforms/bad_projectAxis_remove_too_high_dim] - Failed: DID NOT RAISE ValidationError
FAILED tests/test_attributes.py::test_attributes[spec/invalid/transforms/bad_projectAxis_remove_too_many] - Failed: DID NOT RAISE ValidationError
FAILED tests/test_attributes.py::test_attributes[spec/valid/image/many_space_axes] - jsonschema.exceptions.ValidationError: {'ome': {'version': '0.9.dev1...

Most of these are because they have now become valid, so I'll move them. But these two:

FAILED tests/test_attributes.py::test_attributes[spec/invalid/image/non_existent_orientation] - Failed: DID NOT RAISE ValidationError
FAILED tests/test_attributes.py::test_attributes[spec/invalid/image/non_existent_orientation_type] - Failed: DID NOT RAISE ValidationError

I don't understand why they are failing. Here's the orientation schema, which specifies that the strings must come from specific lists:

https://github.com/jni/ngff-spec/blob/af560df45c0aa987d537e128195bc2dcd454c0a4/schemas/axis_orientation.schema#L11-L43

and here's the relevant part of the files that are unexpectedly passing validation:

https://github.com/jni/ngff-spec/blob/af560df45c0aa987d537e128195bc2dcd454c0a4/tests/attributes/spec/invalid/image/non_existent_orientation.json#L16-L18

https://github.com/jni/ngff-spec/blob/af560df45c0aa987d537e128195bc2dcd454c0a4/tests/attributes/spec/invalid/image/non_existent_orientation_type.json#L26-L29

I'm a noob with jsonschema so I would appreciate any tips or advice here!

vboussot added a commit to vboussot/ngff-zarr that referenced this pull request Aug 20, 2026
The development version that carries RFC-3 is 0.9.dev1. ome/ngff-spec#190
titles the specification 0.9.dev1 and its _version.schema enum holds that
value; bioformats2raw#330 writes the same string.

Renames the package py/ngff_zarr/v10 to v09 and its test module, the
NgffVersion member V10DEV to V09dev1, and the version string in both ports.
LATEST stays 0.6.dev4 and the version stays opt-in.
vboussot added a commit to vboussot/ngff-zarr that referenced this pull request Aug 20, 2026
The development version that carries RFC-3 is 0.9.dev1. ome/ngff-spec#190
titles the specification 0.9.dev1 and its _version.schema enum holds that
value; bioformats2raw#330 writes the same string.

Renames the package py/ngff_zarr/v10 to v09 and its test module, the
NgffVersion member V10DEV to V09dev1, and the version string in both ports.
LATEST stays 0.6.dev4 and the version stays opt-in.
jni added 8 commits August 21, 2026 10:38
Update axes and cooordinate transformations schemas to remove axes
restrictions as per RFC-3.
First, copied schema directly from RFC-4. Then, harmonised it to other
schemas:

- 2 spaces for indents
- schema and ID at top
- ID is NGFF url
- add title and description
- removed additionalproperties, metamodel, and version fields

Added ref to orientation in axes schema and moved orientation def to
top level.
- Add valid image data with axis orientation
- Add invalid orientation attribute files
- Add invalid orientation zarr folders
- xfail duplicate orientation and orientation on non-space axes
  (these can't be easily expressed in jsonschema)
- index.md
- Add 0.9.dev1 to version history
- Update version string in all schemas
- Update version in _version.py
- Update version number on all examples
- Update version string in omero valid test
@jni

jni commented Aug 21, 2026

Copy link
Copy Markdown
Contributor Author

@joshmoore @clbarnes @jo-mueller This should be ready for review. I've also rebased my changes into logical commits to make review easier. Especially if you skip the last commit (which updates the version string in every file), the list of changes should be manageable.

Comment thread tests/test_attributes.py Outdated
case_fnames = sorted(attrs_dir.rglob("*.json"))

xfails = set()
xfails = set([

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extremely minor point: can use a set literal {} here.

Comment thread index.md
"value". Currently, "type" may only be "anatomical", and "value" may
only be one from the list given in [list of possible anatomical
orientation values](orientation-values). A specific orientation value or
its inverse MUST NOT appear more than once in a given coordinate system.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could RECOMMEND TCZYX here for backwards-compatibility, if there's any benefit to that? Or alternatively, add a {hint} that axis ordering could affect performance of certain quries in combination with configuration of the array chunking/ sharding/ transposing.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@clbarnes I'm puzzled about the line you chose to make this comment on? I don't see why axis an orientation note would recommend anything about axis ordering?

At any rate, I think hints about performance can come in future iterations of the 0.9.devN series.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am also puzzled by my choice of line here. Maybe I fat-fingered the touchpad.

Comment thread index.md Outdated
- If there are three spatial axes where two correspond to the image plane (`yx`)
and images are stacked along the other (anisotropic) axis (`z`),
the spatial axes SHOULD be ordered as `zyx`.
0. The length of the axis names MUST match the number of axes of the array.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd be inclined towards 1-basing for ordered lists. The audience is obviously technical but in text 1-based is much more common.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I don't mind fixing that, I didn't because I added it later and it renders as 1-based anyway:

image

So I suggest fixing that in later refinement passes also.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

... But the wrong tick marks in point 5 should definitely be fixed 😂

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok I fixed both the numbering and the quotes.

Comment thread index.md Outdated
@jni jni changed the title WIP: 0.9.dev1 Update spec for 0.9.dev1 Aug 24, 2026
vboussot added a commit to vboussot/ngff-zarr that referenced this pull request Aug 24, 2026
RFC-4 anatomical orientation is normative from OME-Zarr 0.9.dev1
(ome/ngff-spec#190); the released 0.4, 0.5 and 0.6 specs give it no
status. Decided in fideus-labs#667: the three axis-orientation rules and the
readers' raw RFC-4 hooks now gate on the declared version, becoming a
no-op below 0.9.dev1. An omitted version keeps the checks on, as a
strictness choice, exactly like axis-names-unique below 0.9.dev1, so
every existing no-version caller is unchanged.

The gate mirrors the RFC-3 helper's form with the polarity inverted:
RFC-3 lifts axis restrictions at 0.9.dev1 while RFC-4 adds
requirements, so is_rfc4_orientation_enforced exits the rules early
below 0.9.dev1 rather than at it. The Python v0.4 reader now passes
the store's declared version to validate_structural, as the
TypeScript reader already did. The TypeScript v0.6 reader also serves
0.9.dev1, so its hook keeps firing there; a 0.9.dev1 store with a
stray orientation is still refused on read.

No rule is added, renamed or reordered. The parity suites pin the new
version set as CANONICAL_RFC4_VERSIONS in both ports. Two tests that
pinned the old read-path rejection now pin the new acceptance; their
fixtures also carried an (x, y, z) spatial order that the early RFC-4
raise had masked from the structural pass.

Refs fideus-labs#667
vboussot added a commit to vboussot/ngff-zarr that referenced this pull request Aug 24, 2026
RFC-4 anatomical orientation is normative from OME-Zarr 0.9.dev1
(ome/ngff-spec#190); the released 0.4, 0.5 and 0.6 specs give it no
status. Decided in fideus-labs#667: the three axis-orientation rules now gate on
the declared version, becoming a no-op below 0.9.dev1. An omitted
version keeps the checks on, as a strictness choice, exactly like
axis-names-unique below 0.9.dev1, so every existing no-version caller
is unchanged.

The gate mirrors the RFC-3 helper's form with the polarity inverted:
RFC-3 lifts axis restrictions at 0.9.dev1 while RFC-4 adds
requirements, so is_rfc4_orientation_enforced exits the rules early
below 0.9.dev1 rather than at it. The Python v0.4 reader now passes
the store's declared version to validate_structural, as the
TypeScript reader already did.

The readers' raw RFC-4 hooks are removed. They ran validate_rfc4
orientation on the raw axis dicts before parsing, which the
structural pass repeats on the parsed axes with the same function and
the same verdicts (the RFC-4 JSON Schema's root object declares no
properties, so its final pass constrains nothing); they fired before
the structural rules, out of the canonical evaluation order; and the
v0.6 Python hook read a flat axes list the v0.6 layout does not have.
The orientation rule is now the single enforcement point in each
port.

No rule is added, renamed or reordered. The parity suites pin the new
version set as CANONICAL_RFC4_VERSIONS in both ports. Two tests that
pinned the raw hooks' read-path rejection now pin the read-path
acceptance below 0.9.dev1; their fixtures carried an (x, y, z)
spatial order that the hooks' early raise had kept from the
structural pass.

Refs fideus-labs#667
vboussot added a commit to vboussot/ngff-zarr that referenced this pull request Aug 24, 2026
RFC-4 anatomical orientation is normative from OME-Zarr 0.9.dev1
(ome/ngff-spec#190); the released 0.4, 0.5 and 0.6 specs give it no
status. Decided in fideus-labs#667: the three axis-orientation rules now gate on
the declared version, becoming a no-op below 0.9.dev1. An omitted
version keeps the checks on, as a strictness choice, exactly like
axis-names-unique below 0.9.dev1, so every existing no-version caller
is unchanged.

The gate mirrors the RFC-3 helper's form with the polarity inverted:
RFC-3 lifts axis restrictions at 0.9.dev1 while RFC-4 adds
requirements, so is_rfc4_orientation_enforced exits the rules early
below 0.9.dev1 rather than at it. The Python v0.4 reader now passes
the store's declared version to validate_structural, as the
TypeScript reader already did.

The readers' raw RFC-4 hooks are removed. They ran validate_rfc4
orientation on the raw axis dicts before parsing, which the
structural pass repeats on the parsed axes with the same function and
the same verdicts (the RFC-4 JSON Schema's root object declares no
properties, so its final pass constrains nothing); they fired before
the structural rules, out of the canonical evaluation order; and the
v0.6 Python hook read a flat axes list the v0.6 layout does not have.
The orientation rule is now the single enforcement point in each
port.

No rule is added, renamed or reordered. The parity suites pin the new
version set as CANONICAL_RFC4_VERSIONS in both ports. Two tests that
pinned the raw hooks' read-path rejection now pin the read-path
acceptance below 0.9.dev1; their fixtures carried an (x, y, z)
spatial order that the hooks' early raise had kept from the
structural pass.

Refs fideus-labs#667
vboussot added a commit to vboussot/ngff-zarr that referenced this pull request Aug 24, 2026
The development version that carries RFC-3 is 0.9.dev1. ome/ngff-spec#190
titles the specification 0.9.dev1 and its _version.schema enum holds that
value; bioformats2raw#330 writes the same string.

Renames the package py/ngff_zarr/v10 to v09 and its test module, the
NgffVersion member V10DEV to V09dev1, and the version string in both ports.
LATEST stays 0.6.dev4 and the version stays opt-in.
vboussot added a commit to vboussot/ngff-zarr that referenced this pull request Aug 24, 2026
RFC-4 anatomical orientation is normative from OME-Zarr 0.9.dev1
(ome/ngff-spec#190); the released 0.4, 0.5 and 0.6 specs give it no
status. Decided in fideus-labs#667: the three axis-orientation rules now gate on
the declared version, becoming a no-op below 0.9.dev1. An omitted
version keeps the checks on, as a strictness choice, exactly like
axis-names-unique below 0.9.dev1, so every existing no-version caller
is unchanged.

The gate mirrors the RFC-3 helper's form with the polarity inverted:
RFC-3 lifts axis restrictions at 0.9.dev1 while RFC-4 adds
requirements, so is_rfc4_orientation_enforced exits the rules early
below 0.9.dev1 rather than at it. The Python v0.4 reader now passes
the store's declared version to validate_structural, as the
TypeScript reader already did.

The readers' raw RFC-4 hooks are removed. They ran validate_rfc4
orientation on the raw axis dicts before parsing, which the
structural pass repeats on the parsed axes with the same function and
the same verdicts (the RFC-4 JSON Schema's root object declares no
properties, so its final pass constrains nothing); they fired before
the structural rules, out of the canonical evaluation order; and the
v0.6 Python hook read a flat axes list the v0.6 layout does not have.
The orientation rule is now the single enforcement point in each
port.

No rule is added, renamed or reordered. The parity suites pin the new
version set as CANONICAL_RFC4_VERSIONS in both ports. Two tests that
pinned the raw hooks' read-path rejection now pin the read-path
acceptance below 0.9.dev1; their fixtures carried an (x, y, z)
spatial order that the hooks' early raise had kept from the
structural pass.

Refs fideus-labs#667
vboussot added a commit to vboussot/ngff-zarr that referenced this pull request Aug 24, 2026
The development version that carries RFC-3 is 0.9.dev1. ome/ngff-spec#190
titles the specification 0.9.dev1 and its _version.schema enum holds that
value; bioformats2raw#330 writes the same string.

Renames the package py/ngff_zarr/v10 to v09 and its test module, the
NgffVersion member V10DEV to V09dev1, and the version string in both ports.
LATEST stays 0.6.dev4 and the version stays opt-in.
vboussot added a commit to vboussot/ngff-zarr that referenced this pull request Aug 24, 2026
RFC-4 anatomical orientation is normative from OME-Zarr 0.9.dev1
(ome/ngff-spec#190); the released 0.4, 0.5 and 0.6 specs give it no
status. Decided in fideus-labs#667: the three axis-orientation rules now gate on
the declared version, becoming a no-op below 0.9.dev1. An omitted
version keeps the checks on, as a strictness choice, exactly like
axis-names-unique below 0.9.dev1, so every existing no-version caller
is unchanged.

The gate mirrors the RFC-3 helper's form with the polarity inverted:
RFC-3 lifts axis restrictions at 0.9.dev1 while RFC-4 adds
requirements, so is_rfc4_orientation_enforced exits the rules early
below 0.9.dev1 rather than at it. The Python v0.4 reader now passes
the store's declared version to validate_structural, as the
TypeScript reader already did.

The readers' raw RFC-4 hooks are removed. They ran validate_rfc4
orientation on the raw axis dicts before parsing, which the
structural pass repeats on the parsed axes with the same function and
the same verdicts (the RFC-4 JSON Schema's root object declares no
properties, so its final pass constrains nothing); they fired before
the structural rules, out of the canonical evaluation order; and the
v0.6 Python hook read a flat axes list the v0.6 layout does not have.
The orientation rule is now the single enforcement point in each
port.

No rule is added, renamed or reordered. The parity suites pin the new
version set as CANONICAL_RFC4_VERSIONS in both ports. Two tests that
pinned the raw hooks' read-path rejection now pin the read-path
acceptance below 0.9.dev1; their fixtures carried an (x, y, z)
spatial order that the hooks' early raise had kept from the
structural pass.

Refs fideus-labs#667
@joshmoore

Copy link
Copy Markdown
Member

Kudos, @jni! ❤️ For everyone working towards OME-Zarr 1.0, this will be the first of many dev tags. dev2 is likely to be a clean up tag short on the heels of dev1, led by @clbarnes. If there's something you are looking to get in, please get in touch (open an issue, ask on Zulip, etc. etc) to get your very own devX. 😄

@joshmoore
joshmoore merged commit 465dd6f into ome:0.9dev Aug 25, 2026
3 checks passed
@jni
jni deleted the 0.9dev1 branch August 25, 2026 06:22
@sbesson

sbesson commented Aug 25, 2026

Copy link
Copy Markdown
Member

Adding a late 👍 following a discussion yesterday at the weekly OME Formats meeting.

From a consumer perspective, are we expecting the development specification to be published under https://ngff.openmicroscopy.org/specifications/dev/index.html or https://ngff.openmicroscopy.org/specifications/0.9.dev1/index.html? Is that possibly waiting on 0.6.0 to be fully released?

@jni

jni commented Aug 25, 2026

Copy link
Copy Markdown
Contributor Author

dev/ is waiting for 0.6.0 to be released (there can be only one 👨🏴󠁧󠁢󠁳󠁣󠁴󠁿🌩️). 0.9.dev1/ should be served shortly, see ome/ngff#581 for some discussion.

vboussot added a commit to vboussot/ngff-zarr that referenced this pull request Aug 25, 2026
RFC-4 anatomical orientation is normative from OME-Zarr 0.9.dev1
(ome/ngff-spec#190); the released 0.4, 0.5 and 0.6 specs give it no
status. Decided in fideus-labs#667: the three axis-orientation rules now gate on
the declared version, becoming a no-op below 0.9.dev1. An omitted
version keeps the checks on, as a strictness choice, exactly like
axis-names-unique below 0.9.dev1, so every existing no-version caller
is unchanged.

The gate mirrors the RFC-3 helper's form with the polarity inverted:
RFC-3 lifts axis restrictions at 0.9.dev1 while RFC-4 adds
requirements, so is_rfc4_orientation_enforced exits the rules early
below 0.9.dev1 rather than at it. The Python v0.4 reader now passes
the store's declared version to validate_structural, as the
TypeScript reader already did.

The readers' raw RFC-4 hooks are removed. They ran validate_rfc4
orientation on the raw axis dicts before parsing, which the
structural pass repeats on the parsed axes with the same function and
the same verdicts (the RFC-4 JSON Schema's root object declares no
properties, so its final pass constrains nothing); they fired before
the structural rules, out of the canonical evaluation order; and the
v0.6 Python hook read a flat axes list the v0.6 layout does not have.
The orientation rule is now the single enforcement point in each
port.

No rule is added, renamed or reordered. The parity suites pin the new
version set as CANONICAL_RFC4_VERSIONS in both ports. Two tests that
pinned the raw hooks' read-path rejection now pin the read-path
acceptance below 0.9.dev1; their fixtures carried an (x, y, z)
spatial order that the hooks' early raise had kept from the
structural pass.

Refs fideus-labs#667
vboussot added a commit to vboussot/ngff-zarr that referenced this pull request Aug 25, 2026
RFC-4 anatomical orientation is normative from OME-Zarr 0.9.dev1
(ome/ngff-spec#190); the released 0.4, 0.5 and 0.6 specs give it no
status. Decided in fideus-labs#667: the three axis-orientation rules now gate on
the declared version, becoming a no-op below 0.9.dev1. An omitted
version keeps the checks on, as a strictness choice, exactly like
axis-names-unique below 0.9.dev1, so every existing no-version caller
is unchanged.

The gate mirrors the RFC-3 helper's form with the polarity inverted:
RFC-3 lifts axis restrictions at 0.9.dev1 while RFC-4 adds
requirements, so is_rfc4_orientation_enforced exits the rules early
below 0.9.dev1 rather than at it. The Python v0.4 reader now passes
the store's declared version to validate_structural, as the
TypeScript reader already did.

The readers' raw RFC-4 hooks are removed. They ran validate_rfc4
orientation on the raw axis dicts before parsing, which the
structural pass repeats on the parsed axes with the same function and
the same verdicts (the RFC-4 JSON Schema's root object declares no
properties, so its final pass constrains nothing); they fired before
the structural rules, out of the canonical evaluation order; and the
v0.6 Python hook read a flat axes list the v0.6 layout does not have.
The orientation rule is now the single enforcement point in each
port.

No rule is added, renamed or reordered. The parity suites pin the new
version set as CANONICAL_RFC4_VERSIONS in both ports. Two tests that
pinned the raw hooks' read-path rejection now pin the read-path
acceptance below 0.9.dev1; their fixtures carried an (x, y, z)
spatial order that the hooks' early raise had kept from the
structural pass.

Refs fideus-labs#667
vboussot added a commit to vboussot/ngff-zarr that referenced this pull request Aug 25, 2026
"OME-Zarr 0.9.dev1, the version `ome/ngff-spec#190` folds RFC-4 into"
reads the issue number as a version and leaves the verb without an
object. The version is 0.9.dev1; ome/ngff-spec#190 is what incorporates
RFC-4 into it.
@will-moore

Copy link
Copy Markdown
Member

Just looking at https://github.com/ome/ngff-spec/releases/tag/0.9.dev1 it's a shame that page doesn't mention that RFC3 and RFC4 are part of 0.9dev1.
That could possibly be improved a bit by renaming this PR to include RFC3 and RFC4 in the name? Hopefully that will then appear on the 0.9.dev1 page, even if just within the listed PRs.

@jni

jni commented Aug 26, 2026

Copy link
Copy Markdown
Contributor Author

I'm not sure but I don't believe updating the text here will update it on the release page. Still, I'll do it for future releases.

We can also write a more thorough description for 0.9.dev2 which we can tag reasonably quickly.

@jni jni changed the title Update spec for 0.9.dev1 Update spec for 0.9.dev1 including RFCs 3 & 4 Aug 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants