Skip to content

feat(zarr-metadata)!: must_understand false refused at every extension point - #4433

Closed
d-v-b wants to merge 6 commits into
zarr-developers:mainfrom
d-v-b:feat/zarr-metadata-must-understand-extension-points
Closed

d-v-b wants to merge 6 commits into
zarr-developers:mainfrom
d-v-b:feat/zarr-metadata-must-understand-extension-points

Conversation

@d-v-b

@d-v-b d-v-b commented Sep 27, 2026

Copy link
Copy Markdown
Contributor

🤖 AI text below 🤖

One reading of the spec, in its own PR so it can be decided on its own: an array document may not declare any of its extension points ignorable.

What it changes. validate_array_metadata_v3 now refuses must_understand: false on a codec or a storage transformer, as it already did on a data type, a chunk grid and a chunk key encoding. Ignoring a codec gives wrong bytes as surely as ignoring a data type gives wrong values. The spec names only those three points, which this package reads as an oversight rather than a licence. must_understand: false keeps its meaning where it has one: an unknown top-level extension field, which a reader really can skip. The JSON schema that zarr_metadata.pydantic generates for an array document says the same: every extension point has the mandatory envelope, and the test that holds schema and runtime together covers all five.

What breaks. A document that declares a codec or a storage transformer ignorable, which the package accepted before, now has a problem at codecs.N.must_understand or storage_transformers.N.must_understand, so is_array_metadata_v3 says no and parse_array_metadata_v3, from_json and from_key_value raise. The fragment is marked Breaking:. zarr itself does not read through these validators, so what zarr opens is unchanged.

Not in this PR. A metadata field read on its own, outside a document (validate_metadata_field_v3, parse_metadata_field_v3, ZarrV3NamedConfig, the pydantic ZarrV3MetadataField), still takes must_understand: false, and the envelope's allow_must_understand_false keyword stays. The envelope's bool is public API: seventeen TypedDicts and the ZarrV3NamedConfig model declare it. Making the envelope refuse false itself would retype all of them, which is worth doing only once this reading is accepted. Until then a model built by hand can hold what its reader refuses: ZarrV3ArrayMetadata.create_default().update(codecs=(ZarrV3NamedConfig(name="bytes", configuration={}, must_understand=False),)) builds, and its to_key_value, which validates what it writes as the reader does, raises with the problem at codecs.0.must_understand. Closing that gap in the types is the follow-up if the reading is accepted.

Review question: is refusing must_understand: false at codecs and storage transformers the right reading of the spec?

The stack. This is layer 1b of the zarr-metadata stack whose layers 0 (#4420, #4421, #4422) and 1 (#4432, the TypedDict checker) have merged. It is based on main and stands alone. The later layers are open on my fork: metadata fields read against their definitions (d-v-b#350, with its core reviewable alone in d-v-b#349), then the field in a document (d-v-b#355). They apply the same refusal when they judge a field's envelope, and a test there holds the two readers together at all five points, so if this reading is rejected, those call sites change with it.

🤖 Generated with Claude Code

d-v-b and others added 4 commits September 27, 2026 11:59
… point

Ignoring a codec gives wrong bytes as surely as ignoring a data type
gives wrong values, so no extension point may be declared ignorable:
`validate_array_metadata_v3` now refuses `must_understand: false` on a
codec or a storage transformer, as it already did on a data type, a
chunk grid and a chunk key encoding. The spec names only those three,
which this package reads as an oversight rather than a licence.
`must_understand: false` keeps its meaning where it has one: an unknown
top-level extension field, which a reader really can skip.

It changes verdicts and nothing else depends on it, so it stands on its
own as a reading of the spec. The definition layer above reads every
metadata field under the same policy.

Assisted-by: ClaudeCode:claude-opus-5-5
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…verywhere

Assisted-by: ClaudeCode:claude-opus-5-5
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ere the validator does

The JSON schema the pydantic integration generates typed a codec and a
storage transformer with the envelope that allows `must_understand:
false`, so it accepted an array document the validator refuses. Every
extension point of an array document now has the mandatory envelope,
and the test that holds schema and runtime together covers all five.
A metadata field read on its own keeps the general envelope, as
`parse_metadata_field_v3` does.

Assisted-by: ClaudeCode:claude-opus-5-5
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The comment linked the section's opening rules, not the sentence that limits `must_understand=False` to three extension points.

Assisted-by: ClaudeCode:claude-opus-5-5
@github-actions github-actions Bot added needs release notes Automatically applied to PRs which haven't added release notes zarr-metadata Specific to the zarr-metadata sub-package labels Sep 27, 2026
…t breaks

Assisted-by: ClaudeCode:claude-opus-5-5
@read-the-docs-community

Copy link
Copy Markdown

Documentation build overview

📚 zarr-metadata | 🛠️ Build #34784666 | 📁 Comparing b510d0a against latest (c383b22)

  🔍 Preview build  

1 file changed
± api/model/index.html

@d-v-b
d-v-b marked this pull request as ready for review September 27, 2026 10:08
@codecov

codecov Bot commented Sep 27, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 94.37%. Comparing base (8dc50b8) to head (69ed30c).

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #4433   +/-   ##
=======================================
  Coverage   94.37%   94.37%           
=======================================
  Files          93       93           
  Lines       13174    13174           
=======================================
  Hits        12433    12433           
  Misses        741      741           
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

d-v-b added a commit to d-v-b/zarr-python that referenced this pull request Sep 27, 2026
…erged it

The change merged with zarr-developers#4434, which carried zarr-developers#4433's commits; towncrier links a fragment to the pull request its name gives.

Assisted-by: ClaudeCode:claude-opus-5-5
@d-v-b

d-v-b commented Sep 27, 2026

Copy link
Copy Markdown
Contributor Author

🤖 AI text below 🤖

Landed with #4434, which carried these commits (squash 8dc50b81b), so main already holds everything here and there is nothing left to merge. #4436 renames this PR's changelog fragment to 4434.feature.1.md, so the entry links the PR that merged it.

@d-v-b d-v-b closed this Sep 27, 2026
@d-v-b
d-v-b deleted the feat/zarr-metadata-must-understand-extension-points branch September 27, 2026 12:06
d-v-b added a commit that referenced this pull request Sep 27, 2026
…s definition (#4436)

* feat(zarr-metadata): the model reads each extension point through its definition

`validate_array_metadata_v3` judged an array document's structure and
left every configuration unread: a gzip `level` of 99, or a key a codec
does not declare, passed. It now reads each extension point -- the data
type, the chunk grid, the chunk key encoding, each codec and each
storage transformer -- with `resolve`, in a scope,
`CORE_AND_EXTENSIONS` unless a `context` is passed: the envelope judged,
`must_understand: false` refused at each, and the configuration read
against the definition that claims its name. A name nothing in scope
claims is left unjudged, which keeps the format open.

So do the `is_*` and `parse_*` beside it and the v3 group validators,
with each array an inline `consolidated_metadata` holds, and the v3
model classes' `from_json` and `from_key_value` take the same
`context`, so a reader that substitutes its own reading of a codec
builds the model from a document its scope accepts. The pydantic types
read in `CORE_AND_EXTENSIONS`, since a field type holds no scope; the
docstrings and the definition guide say so, and say that no rule here
reads one field against another.

Assisted-by: ClaudeCode:claude-opus-5-5
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(zarr-metadata): the validation boundary says what the validators read

The README and the docs index said the model validators do not
interpret extension names or configurations. In a v3 document they now
read each extension point through its definition in a scope, refuse
what the definition refuses and report an undeclared key as
`unknown_key`; they leave names nothing claims unjudged, and do not
judge fields against each other.

Assisted-by: ClaudeCode:claude-opus-5-5
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(zarr-metadata): the fragment for the model reading extension points through definitions

Assisted-by: ClaudeCode:claude-opus-5-5
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(zarr-metadata): a v3 model writes in the scope it reads in

`to_key_value` validates what it writes with its reader's `parse_*`,
and at this layer the reader reads each extension point in a scope. The
v3 array and group `to_key_value` take the same `context` as `from_json`
and `from_key_value`, so a model read with a reader's own definitions is
written with them, and the default scope still refuses to write what it
would refuse to read.

Assisted-by: ClaudeCode:claude-opus-5-5

* docs(zarr-metadata): the fragment takes this PR's number and says what breaks

Assisted-by: ClaudeCode:claude-opus-5-5

* docs(zarr-metadata): the must_understand fragment names the PR that merged it

The change merged with #4434, which carried #4433's commits; towncrier links a fragment to the pull request its name gives.

Assisted-by: ClaudeCode:claude-opus-5-5

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs release notes Automatically applied to PRs which haven't added release notes zarr-metadata Specific to the zarr-metadata sub-package

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant