Conversation
|
Reviewed from the consumer side: I ran the cases in this PR against PyIceberg on current The geospatial cases work exactly as intended, and they catch a live defect. Spelling "unquoted" into the clauses was the right call. PyIceberg's The decimal whitespace case stops one step short of the interesting input. On the |
laskoviymishka
left a comment
There was a problem hiding this comment.
Good first cut. The base/types schema split makes sense, expected values come from the spec rather than one implementation, and the JSON Schema validator + RAT in CI give us a useful starting point. Also good that moomindani already ran this against PyIceberg and found a real divergence.
I’d still hold the merge for a few things, mainly because this becomes the contract other implementations will validate against.
The biggest one is geospatial serialization. A few geometry/geography cases describe the canonical serialized form in the clause but don’t have a canonical field. moomindani’s run shows why that matters: PyIceberg writes the quoted CRS form, while Java reads those quotes into the CRS itself, so the two sides diverge (apache/iceberg-python#3530). I’d add canonical to those cases and settle the default-CRS form here.
The decimal whitespace case is a bit different. decimal-9-2-spaced currently uses decimal(9, 2), which all the implementations checked already accept, so it doesn’t really distinguish strict vs lenient parsing. The more useful case is decimal( 9 , 2 ) from apache/iceberg#16798: PyIceberg rejects it and Java accepts it, and both are still conformant. That probably means this needs a small normative distinction, e.g. optional normative_level with default must, so a SHOULD case isn’t encoded as MUST.
Before merge I’d fix:
- add
canonicalto the geospatial cases that already pin the serialized form, and decide the default-CRS representation - change the decimal whitespace fixture to
decimal( 9 , 2 )and add optional normative level - pin the
jsonschemadependency and add one negative self-test so CI proves the validator can fail - set
additionalProperties: falseon the case schema so typos don’t silently pass
The rest is in the inline comments. After these, I’m happy to take another look.
| "valid": true, | ||
| "input": "geometry(OGC:CRS84)", | ||
| "decoded": {"type": "geometry", "crs": "OGC:CRS84"}, | ||
| "clause": "geometry(C) with explicit CRS; the canonical serialized form is unquoted \"geometry(<C>)\"", |
There was a problem hiding this comment.
The clause here says the canonical form is the unquoted geometry(OGC:CRS84), but without a canonical field the write direction never gets tested — an implementation that emits geometry('OGC:CRS84') or GEOMETRY(OGC:CRS84) would pass. Since the clause already pins the spelling, I'd add canonical to each explicit case: "canonical": "geometry(OGC:CRS84)" here, "geography(OGC:CRS84, spherical)" on the geography ones, and so on. Same applies to geometry-srid and the four geography algorithm cases below.
moomindani's consumer-side run makes this concrete: PyIceberg's regex requires a quoted CRS, so it rejects geometry(srid:4326) and writes geometry('srid:4326'), while Java reads the quotes into the CRS — a silent bidirectional divergence this fixture catches once canonical pins the write side (they filed apache/iceberg-python#3530).
| { "id": "fixed-1", "valid": true, "input": "fixed[1]", "decoded": { "type": "fixed", "length": 1 }, "canonical": "fixed[1]", "clause": "Appendix C: fixed canonical string is fixed[<L>]", "spec_ref": "format/spec.md#appendix-c-json-serialization" }, | ||
| { "id": "fixed-16", "valid": true, "input": "fixed[16]", "decoded": { "type": "fixed", "length": 16 }, "canonical": "fixed[16]", "clause": "Appendix C: fixed canonical string is fixed[<L>]", "spec_ref": "format/spec.md#appendix-c-json-serialization" }, | ||
| { "id": "decimal-9-2", "valid": true, "input": "decimal(9,2)", "decoded": { "type": "decimal", "precision": 9, "scale": 2 }, "clause": "Appendix C: both decimal(9,2) and decimal(9, 2) are canonical, so no byte-exact form is pinned", "spec_ref": "format/spec.md#appendix-c-json-serialization" }, | ||
| { "id": "decimal-9-2-spaced", "valid": true, "input": "decimal(9, 2)", "decoded": { "type": "decimal", "precision": 9, "scale": 2 }, "clause": "Appendix C: the spaced decimal(9, 2) form parses to the same decimal", "spec_ref": "format/spec.md#appendix-c-json-serialization" }, |
There was a problem hiding this comment.
moomindani's consumer-side run reframed this one for me: decimal(9, 2) is accepted by every implementation they checked, so as written this case is inert — it doesn't separate a strict parser from a lenient one. The input that does is the broader form apache/iceberg#16798 actually added, "whitespace around parameters and separators": PyIceberg rejects decimal( 9 , 2 ) / decimal(9 ,2) while Java accepts them, and both are conformant.
That's the case I'd want on this surface (the sungwy/iceberg-testing prototype carried it, noting "a reader stricter than that diverges here"). But because both parsers are conformant on it, it can't be a plain valid: true — a MUST-accept would fail PyIceberg for behavior the spec only recommends. So I'd swap in the divergent decimal( 9 , 2 ) input and give it a normative tier: an optional normative_level on the base schema (default "must") with this case marked as the SHOULD, so runners treat it as advisory rather than a hard fail.
I'd leave canonical off the decimal cases as you have it — agreed the pinned-spelling question is spec text, not something to settle in a fixture. wdyt on the normative tier?
There was a problem hiding this comment.
I put in a normative_level for now, but I'd like to hear from others if that's good enough.
There was a problem hiding this comment.
The tier reads right to me, and the wording it encodes is already in the spec: format/spec.md:1693 says readers should accept the optional whitespace, so a reader that rejects decimal( 9 , 2 ) stays conformant and a plain MUST-accept fixture would fail it for behavior that is only recommended. Defaulting to must also means no existing case changes meaning.
One thing worth writing into the schema description while it is fresh: a runner has to report a failed SHOULD distinctly from a pass, otherwise the advisory tier is invisible in practice and contributors will assume the case is inert again.
|
Added @szehon-ho here to add some perspective on Geo and how we should represent them. Also, CC: @huan233usc |
7e0a119 to
2bc32a5
Compare
2bc32a5 to
63064f3
Compare
Rationale for this change
Adds the first conformance surface: spec-derived type fixtures under
table-spec/types/(parse(input) == decoded, withvalidmarking accept vs reject), validated by JSON Schema. Runners that exercise the fixtures against each implementation follow in later PRs.Are these changes tested?
Yes.
dev/validate-fixtures.pyvalidates everycases.jsonagainst the schemas and the unique-id rule in CI, anddev/check-licenseruns Apache RAT.Are there any user-facing changes?
No.
AI Disclosure
Developed with Claude (Claude Code); fully reviewed by the author.