Conversation
d-v-b
force-pushed
the
layer/1-checker
branch
from
September 22, 2026 19:08
e73a9ee to
5b7ae46
Compare
d-v-b
force-pushed
the
layer/2a-field
branch
2 times, most recently
from
September 23, 2026 01:09
793383a to
0200d39
Compare
d-v-b
added a commit
that referenced
this pull request
Sep 23, 2026
The JSON-first version of the one-field layer, beside #349's dataclass-first one. The type check stands alone and feeds the rules; nothing is built from a configuration to judge it. A definition is a value: the name the metadata carries, the TypedDict its configuration is -- the one declaration of that JSON, which the checker is compiled from -- and plain functions over that TypedDict for the rules. Its kind is its type (`CodecDefinition`, `ChunkGridDefinition`, ...), and a generic frozen dataclass checks itself in `__post_init__`: no `__init_subclass__`, no metaclass, no abstract base. A scope holds definitions by kind. Three steps, each usable on its own by a caller holding JSON: `check` (JSON against a TypedDict, no scope; a nested field, annotated `CodecField`, is an envelope), `Definition.judge` (the check, then the rules), and `resolve` (a whole field in a scope, returning `Resolved` with a `Resolution` and every problem located). gzip, bytes, crc32c and the regular grid are defined, with the verdicts #349 gives them. 1,160 lines over the checker, against #349's 2,334; `_definition.py` is 471 lines where `_entity.py` is 1,024. Assisted-by: ClaudeCode:claude-opus-5-5 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
d-v-b
force-pushed
the
layer/2a-field
branch
from
September 23, 2026 01:17
0200d39 to
2b3a25c
Compare
d-v-b
force-pushed
the
layer/2a-field
branch
from
September 23, 2026 07:48
2b3a25c to
862fdca
Compare
d-v-b
force-pushed
the
layer/1-checker
branch
from
September 23, 2026 09:01
af5bb8f to
59eaac5
Compare
d-v-b
force-pushed
the
layer/2a-field
branch
from
September 23, 2026 09:01
862fdca to
67eb376
Compare
This was referenced Sep 23, 2026
d-v-b
force-pushed
the
layer/1-checker
branch
from
September 23, 2026 09:19
59eaac5 to
4325bce
Compare
d-v-b
force-pushed
the
layer/2a-field
branch
from
September 23, 2026 09:19
67eb376 to
242dd6b
Compare
d-v-b
marked this pull request as draft
September 23, 2026 09:19
d-v-b
force-pushed
the
layer/1-checker
branch
from
September 23, 2026 09:51
4325bce to
f7a7296
Compare
d-v-b
force-pushed
the
layer/2a-field
branch
from
September 23, 2026 09:51
242dd6b to
68415f6
Compare
d-v-b
changed the base branch from
layer/1-checker
to
layer/0b-must-understand
September 23, 2026 09:51
d-v-b
force-pushed
the
layer/0b-must-understand
branch
from
September 23, 2026 10:50
00b51ef to
739a214
Compare
d-v-b
force-pushed
the
layer/2a-field
branch
from
September 23, 2026 10:50
68415f6 to
205dc76
Compare
d-v-b
force-pushed
the
layer/0b-must-understand
branch
from
September 23, 2026 11:39
739a214 to
214695c
Compare
d-v-b
force-pushed
the
layer/2a-field
branch
from
September 23, 2026 11:39
205dc76 to
5c281d3
Compare
d-v-b
force-pushed
the
layer/0b-must-understand
branch
from
September 26, 2026 15:19
214695c to
7b139f6
Compare
d-v-b
force-pushed
the
layer/2a-field
branch
from
September 26, 2026 15:19
5c281d3 to
3bfba30
Compare
d-v-b
force-pushed
the
layer/0b-must-understand
branch
from
September 26, 2026 16:16
7b139f6 to
c6ca89b
Compare
d-v-b
force-pushed
the
layer/2a-field
branch
from
September 26, 2026 16:16
3bfba30 to
113da76
Compare
d-v-b
force-pushed
the
layer/0b-must-understand
branch
from
September 26, 2026 20:06
c6ca89b to
e201dd6
Compare
d-v-b
force-pushed
the
layer/2a-field
branch
from
September 26, 2026 20:06
113da76 to
457c5c6
Compare
The one-field layer, JSON first: the type check stands alone and feeds the rules, and nothing is built from a configuration to judge it. A definition is a value: the name the metadata carries, the TypedDict its configuration is -- the one declaration of that JSON, which the checker is compiled from -- and plain functions over that TypedDict for the rules. Its kind is its type (`CodecDefinition`, `ChunkGridDefinition`, ...), and a generic frozen dataclass checks itself in `__post_init__`: no `__init_subclass__`, no metaclass, no abstract base. A scope holds definitions by kind. Three steps, each usable on its own by a caller holding JSON: `check` (JSON against a TypedDict, no scope: #347's, re-exported), `Definition.judge` (the check, each nested field's envelope judged -- a member annotated `CodecField` holds one -- then the rules), and `resolve` (a whole field in a scope, returning `Resolved` with a `Resolution` and every problem located). gzip, bytes, crc32c and the regular grid are defined. What the rules are handed is what the type says: a configuration holding the keys its TypedDict admits and nothing else, whose nested fields' envelopes are sound, so a rule may index a table by key or read a nested field's name; a rule's problems land in the configuration in `judge` and `resolve` alike. The checker hands nested fields back in the typed value, so the branch of a union that did not match reads none. A definition refuses at build what it could not read with -- a TypedDict that says nothing of the keys it does not declare, a member typed `ZarrV3MetadataFieldJSON`, an annotation that does not resolve, a name that is not a string, a codec kind outside the three, rules or `names` that are not functions -- and a field is read as one of the five kinds, with or without type arguments, anything else a `TypeError`. `configuration_of` types a read configuration as its definition's TypedDict, and the configuration's type parameter has a default, so `resolve(field, CodecDefinition, scope)` infers nothing unknown. The definitions read JSON and its problems from `zarr_metadata._json`, and a metadata field's own validators from `zarr_metadata.v3._common`, where they move from the model, so nothing this layer adds imports the model it supports. Assisted-by: ClaudeCode:claude-opus-5-5 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
d-v-b
force-pushed
the
layer/0b-must-understand
branch
from
September 27, 2026 10:20
e201dd6 to
b510d0a
Compare
d-v-b
force-pushed
the
layer/2a-field
branch
from
September 27, 2026 10:20
457c5c6 to
2615b87
Compare
Owner
Author
|
🤖 AI text below 🤖 The review slice for the single-field design, which landed inside zarr-developers#4434 (squash |
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 🤖
Since this slice was cut: zarr-developers#4434 (#350) has no families.
namesandname_rulesare gone; raw bits read asr*with the size their name carries (r16isr*with{"bits": 16}), soclaimantis a dict lookup. This slice keeps its first commit as it was, so what it says of families below is superseded.A review slice, not a landing PR. This is 2a alone, to review the design for a single field. It lands inside #350, which carries this commit with 2b. On its own its
COREholds four definitions and would answerout_of_scopefor a core data type likeint8, which the guide defines as an extension nobody models. It is a draft so it cannot merge alone. Review fixes go on the upstream branch of zarr-developers#4434, whichlayer/2b-definitions(#350) mirrors; this branch carries the same first commit, rebuilt when that one changes.Layer 2a of the stack, on top of #353: one metadata field read against its definition. The design for a single field, with four worked definitions; every other extension is the next PR, which interpolates this one.
The design. The type check stands alone and feeds the rules; nothing is built from a configuration to judge it. A definition is a value, not a class to subclass: the
namethe metadata carries, the TypedDict itsconfigurationis (the one declaration of that JSON, which the checker from zarr-developers#4432 is compiled from), andrules, a plain function over that TypedDict yielding what the spec disallows. Its kind is its type:CodecDefinition(with the codec'skind),DataTypeDefinition,ChunkGridDefinition,ChunkKeyEncodingDefinition,StorageTransformerDefinition.Definition[C]is a generic frozen dataclass that checks itself in__post_init__; there is no__init_subclass__, metaclass or abstract base.Three steps, each usable on its own by a caller holding only JSON:
check(value, SomeTypedDict): JSON against a TypedDict, no scope needed. It iszarr_metadata.typed_json.check, from feat(zarr-metadata): check, JSON against a TypedDict as the typing spec reads it zarr-developers/zarr-python#4432, re-exported here. What comes back holds what the TypedDict admits and nothing else. A member holding another metadata field is annotated with a field alias,CodecField, and checked as the JSON a metadata field is.definition.judge(configuration): the check, each nested field's envelope judged (a stray member, amust_understandoffalse), then the rules. A rule never meets a member of the wrong type, a key its TypedDict does not declare, or a nested field whose envelope is broken, so it may index a table by key or read a nested field's name.resolve(field, CodecDefinition, scope): a whole field read in a scope. The envelope is judged, the name related to a definition throughContext.claimant, the configuration judged, and each nested field read the same way. It returnsResolved, with aresolutionofLiteral["read"] | Unread, and every problem located. A name nothing in scope claims isout_of_scope, which keeps the format open. A field is read as one of the five kinds, with or without type arguments; anything else is aTypeError.configuration_of(resolved, GZIP_CODEC)is the configuration typed as that definition's TypedDict.What a definition refuses when it is built, each a
TypeErrorsaying what is wrong: a configuration that is not a TypedDict, says nothing of the keys it does not declare, or has a member no checker reads, named down to the TypedDict that holds it; a member typedZarrV3MetadataFieldJSON, which would check as plain JSON and never be read as a field; a name that is not a string; rules ornamesthat are not functions; a codec kind outside the three.A scope holds definitions by kind:
Context.of(*definitions),extended_with,claimant. It refuses a definition of no kind. A family claims many names throughnamesand judges them throughname_rules.Worked definitions:
GZIP_CODEC(a configured codec with a rule),BYTES_CODEC(an optional member),CRC32C_CODEC(nothing to configure),REGULAR_CHUNK_GRID(a tuple member with a rule).COREholds those four;CORE_AND_EXTENSIONSequals it until 2b.Not here yet. Nothing that needs the document or the array: no fill values against a data type, no codec transitions, no pipeline order.
Since the first version, from a design review, each with a test: a container's rule no longer raises on a nested field without a name; unknown keys no longer reach the rules or the typed value; a
ZarrV3MetadataFieldJSONmember, a kind nothing is filed under, and a malformed definition are refused rather than silently unread; a union's rejected branch no longer leaks nested fields; a rule's problem lands on the configuration inresolveas injudge; andresolve(field, CodecDefinition, scope)now type-checks under strict pyright, through a default on the configuration's type parameter. From the stack's design review:read_field, which nothing here called, is gone. From the second: a metadata field's own validators move tozarr_metadata.v3._commonand the definitions import JSON and its problems fromzarr_metadata._json, so nothing this layer adds imports the model it supports.Also here: the door's docs page,
zarr_metadata.v3.definition, whose docstring is the guide, and the public-name grammar'sDefinitionandFieldroles.Size: about 1,700 lines over #353, 1,100 of them source; the member-naming walk and the type check itself live in the checker, merged upstream as zarr-developers#4432.
Review question for this layer: for one field, is this the right shape, and is the door's guide enough to write an extension from?
The stack: 0 model groundwork, merged upstream as zarr-developers#4420, zarr-developers#4421 and zarr-developers#4422 → 1 the checker, merged upstream as zarr-developers#4432 → 1b
must_understand: falserefused at every extension point (#353, upstream as zarr-developers#4433) → 2a this, landing in #350 → 2b every extension (#350, upstream as zarr-developers#4434) → 3 the field in a document → 4 the field among fields.🤖 Generated with Claude Code