feat(zarr-metadata)!: the model reads each extension point through its definition - #4436
Merged
d-v-b merged 6 commits intoSep 27, 2026
Merged
Conversation
… 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>
… 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>
…nts through definitions Assisted-by: ClaudeCode:claude-opus-5-5 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`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
…t breaks Assisted-by: ClaudeCode:claude-opus-5-5
…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
Documentation build overview
5 files changed ·
|
d-v-b
marked this pull request as ready for review
September 27, 2026 11:37
This was referenced Sep 27, 2026
This was referenced Sep 28, 2026
Closed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
🤖 AI text below 🤖
The model reads each extension point of a v3 document through its definition.
validate_array_metadata_v3judged an array document's structure and left every configuration unread, so a gziplevelof 99, or a key a codec does not declare, passed. It now reads the data type, the chunk grid, the chunk key encoding, each codec and each storage transformer withresolve(#4434), in a scope:CORE_AND_EXTENSIONSunless acontextis passed. A name nothing in scope claims is left unjudged, which keeps the format open.What reads in a scope. The
is_*andparse_*beside it read the same way, as do the v3 group validators and each array an inlineconsolidated_metadataholds, with problems located down to the member:('consolidated_metadata', 'metadata', 'a', 'codecs', 1, 'configuration', 'level'). Each takescontext=, and so do the v3 model classes'from_json,from_key_valueandto_key_value.to_key_valuevalidates what it writes in that scope, so the model never writes what its reader in the same scope refuses, and a reader that substitutes its own reading of a codec can build the model from a document its scope accepts and write it back. The pydantic types read inCORE_AND_EXTENSIONS, since a field type holds no scope; the module docstring says so, and how a reader with its own scope callsfrom_jsoninstead.What breaks. A document whose configurations its definitions refuse, which
mainaccepts, now has problems:is_*says no, andparse_*,from_jsonandfrom_key_valueraise. The fragment is marked Breaking:. A key a configuration does not declare is reported asunknown_keyand the field is still read, so a consumer that tolerates one can filter problems by kind.Docs. The README and the docs index said the model validators do not interpret extension names or configurations. They now say what the validators read, what they leave unjudged, and that no rule reads one field against another. The definition guide shows a scope reading a whole document.
Not checked here. Every rule that reads one field against another waits for the next layer:
endianfor a multi-byte type;scaleandoffsetagainst the data type;chunksagainst itsshape.Cost. Validating a document now reads its configurations. On CPython 3.13, best of several runs, a simple array document takes about 20 µs where
maintakes about 5 µs, and a sharded one about 45 µs wheremaintakes about 12 µs. A group'sfrom_jsonvalidates each array its consolidated metadata holds three times, five inside a nested group, asmaindoes; each pass now costs this much more. Validating each array once is a follow-up.Not here.
zarr_metadata.pydanticgenerates describes each extension point's envelope, not its configuration, so it accepts a gziplevelof 99 that the runtime refuses.invalid_value, where the checker reportsunknown_key, even for the inline consolidated envelope, whose TypedDict is closed. Making those kinds agree changes the kindsmainreports, not its verdicts, so it is its own change.unknown_keyis onmainsince feat(zarr-metadata): check, JSON against a TypedDict as the typing spec reads it #4432, so that change should land before the next release.Also here. The
must_understandfragment onmain,4433.feature.md, is renamed4434.feature.1.md: that change merged with #4434, and #4433 now has nothing left to merge.Review question: is reading each extension point through its definition, in a scope the caller can replace, the right shape for the document's reader?
The stack. Layers 0 (#4420, #4421, #4422), 1 (#4432) and 2 (#4434, which carried #4433's
must_understandchange) have merged. This is layer 3, based onmain. Layer 4, the field among fields, reads the rules listed above and is not written yet.🤖 Generated with Claude Code