Files
greptimedb/tests/compatibility/wire/raw_series_label_decode

Raw-series label decode description compatibility

v2_metadata.json is a hand-authored, frozen set of Arrow schema metadata maps for the v2 series frame. It records the established layout/content/labels/time metadata plus the greptime.series.label_decode entry, whose value is a JSON label decode description with an explicit version. The Rust unit test parses these literal maps through series_frame_label_decode; the fixture is not produced by the schema builder. v1_physical_types.json, described under Physical types, is the one generated fixture here: it records the serde text of every ConcreteDataType variant, which the frame layout version does not change, so it keeps its original name.

Run the focused check:

cargo nextest run -p datatypes -E 'test(raw_series_label_decode_metadata_fixture)'

The fixture proves that a key-encoded frame's description decodes for both primary-key encodings, that the ordered key columns and logical tags survive the wire form with a mixed physical type set, that a logical tag must name a listed key column, and that the reader rejects a key frame without a description, an explicit frame that declares one, an unknown version, a missing or unknown field, a wrong field type, and a non-JSON value.

It also pins the declarations the unified frame family refuses. Layout is now v2: a frame declaring v1 or any other value is refused, and so is a greptime.series.* key this revision does not register. The three modes are not independent - content fixes time, and labels decides whether a description must be present - so content = evaluated with time = timestamps, content = evaluated with labels = key, and content = raw with a greptime.series.grid are all contradictions and are refused rather than half-trusted. An evaluated frame is therefore always explicit + grid_spans and always declares its grid; a raw frame is always timestamps and never declares one.

A timestamp-typed tag column has its own case in the crate's unit tests rather than here, so this fixture stays a single fixed layout.

The fixture does not prove interoperability with an old binary, nor does it test an end-to-end client or service. Separate pack and IPC tests check that a packed stream declares the description derived from its binding and that it agrees with the schema a consumer receives.

greptime.series.* metadata is compared as exact text by remote merges, so the text stored here is what the single writer produces: compact JSON in declaration order. A reader must never regenerate it differently; semantically equal text with different whitespace is a mismatch, not an accepted variant.

The description is versioned independently of the surrounding frame layout: a reader rejects any version it does not implement instead of guessing, so a future revision must add a new fixture case rather than relax this one.

Physical types

physical_type is ConcreteDataType's own serde form, so this description's text embeds the serialization of a type defined in src/datatypes/src/data_type.rs and its types/ modules. That shape is not restated or owned here: whatever ConcreteDataType's serde writes is what a description carries, and the two spellings that appear below — {"String":{"size_type":"Utf8"}} and {"UInt32":{}} — are examples of it rather than a vocabulary this fixture defines.

What freezes that shape is v1_physical_types.json: one entry per ConcreteDataType variant, {"variant": "<name>", "text": "<serde_json>"}, with text generated from serde_json::to_string rather than written by hand. The crate's every_datatype_round_trips_through_its_frozen_text test fails when a variant's serde no longer parses back or no longer re-serializes to the frozen text, and the_frozen_text_covers_every_datatype_variant fails when a variant of ConcreteDataType has no entry, because its exhaustive match names every variant. Changing ConcreteDataType's serde, or any text recorded here, changes the text two nodes compare, so it requires bumping LABEL_DECODE_VERSION and regenerating this fixture together.

logical_tags is written in the writer's canonical order (sorted by (column_id, name)). The order carries no meaning — the decoder sorts tags by name when it binds them — but fixing it means two producers of the same labels write the same bytes, which is what lets the same equality rule serve both a local comparison and the byte-exact remote one. The writer canonicalizes a copy of the description for exactly that reason, leaving the caller's binding order alone.

Run the physical-type check too:

cargo nextest run -p datatypes -E 'test(datatype) or test(frozen_text)'