From 6b829db01b483e567460914db24bbc874612f470 Mon Sep 17 00:00:00 2001 From: Brendan Collins Date: Sun, 24 May 2026 04:22:03 -0700 Subject: [PATCH 1/2] Add GeoTIFF release-contract docs page (#2347) Adds docs/source/reference/geotiff_release_contract.md with the user-facing meaning of every support tier (stable, advanced, experimental, internal-only, unsupported) and a feature-tier table covering every entry in SUPPORTED_FEATURES (codecs, readers, writers) plus the unsupported combinations from epic #2340. Links the new page from the seealso block in geotiff.rst and adds it to the reference toctree in index.rst. Docs-only. No changes to _attrs.py, public API docstrings, opt-in enforcement, or tests; those are parallel PRs under epic #2340. --- docs/source/reference/geotiff.rst | 5 + .../reference/geotiff_release_contract.md | 136 ++++++++++++++++++ docs/source/reference/index.rst | 1 + 3 files changed, 142 insertions(+) create mode 100644 docs/source/reference/geotiff_release_contract.md diff --git a/docs/source/reference/geotiff.rst b/docs/source/reference/geotiff.rst index 4e06acc6..40a3f108 100644 --- a/docs/source/reference/geotiff.rst +++ b/docs/source/reference/geotiff.rst @@ -6,6 +6,11 @@ GeoTIFF / COG .. seealso:: + :ref:`reference-geotiff-release-contract` -- the user-facing release + contract that defines what each support tier promises and lists every + feature in :data:`xrspatial.geotiff.SUPPORTED_FEATURES` against its + tier. + :ref:`reference.geotiff_release_gate` -- the release gate / audit checklist that lists every promised feature on this page, its tier, its one-line acceptance, and the regression test that locks it. diff --git a/docs/source/reference/geotiff_release_contract.md b/docs/source/reference/geotiff_release_contract.md new file mode 100644 index 00000000..164ed32e --- /dev/null +++ b/docs/source/reference/geotiff_release_contract.md @@ -0,0 +1,136 @@ +(reference-geotiff-release-contract)= + +# GeoTIFF release contract + +This page is the user-facing release contract for the GeoTIFF module. It defines +what each support tier promises and lists every feature exposed through +`xrspatial.geotiff.SUPPORTED_FEATURES` against its tier. + +The tier strings here match the strings in `xrspatial.geotiff.SUPPORTED_FEATURES` +at runtime. If a feature is not in the table below, it is unsupported for this +release. + +See also: the {ref}`release gate / audit checklist ` +for the per-feature regression test that locks each promise, and the main +{ref}`GeoTIFF reference ` for the API surface. + +## What each tier promises + +### stable + +A `stable` feature is part of the release contract. It is covered by regression +tests in CI, and a behavioural regression fails the build. The on-disk format, +the metadata round-trip, and the public function signature are expected to keep +working across patch releases. Removals or breaking changes go through a +deprecation window. You can rely on these in production. + +### advanced + +An `advanced` feature works and is tested, but its surface may change before a +1.0 release. Behaviour is documented and exercised by tests, but the contract is +narrower than `stable`. Edge cases on rare codecs, transport quirks on HTTP, and +metadata interop with the wider GDAL ecosystem are not all pinned down. Use +these in production with the expectation that you may need to follow a +release-note migration. + +### experimental + +An `experimental` feature exists and is covered by smoke tests, but it carries +no behavioural promise. Output may change without a deprecation window, error +paths may shift, and cross-backend numerical parity is not claimed. Some +experimental features require an explicit opt-in flag +(`allow_experimental_codecs=True` for the experimental codecs, for example) so +they do not get used by accident. Treat experimental features as something to +evaluate, not depend on. + +### internal-only + +An `internal_only` feature exists for one specific xrspatial use case. It is not +interoperable with the wider GeoTIFF ecosystem (GDAL, libtiff, rasterio) and is +not part of the public surface. The JPEG-in-TIFF writer is the current example: +it requires the dedicated `allow_internal_only_jpeg=True` opt-in and is +documented as not externally readable. Do not build on internal-only features. + +### unsupported + +`unsupported` is a doc-only tier. It captures combinations that are out of +contract for this release. Calling them either fails with an actionable error +or is documented as not supported. The list is here so release notes do not +accidentally imply coverage that does not exist. `unsupported` is not a key in +`xrspatial.geotiff.SUPPORTED_FEATURES`; it lives only on this page. + +## Feature tier table + +The table groups every entry in `xrspatial.geotiff.SUPPORTED_FEATURES` by +category. The `Key` column matches the runtime key. + +### Codecs + +| Key | Tier | Notes | +| --- | --- | --- | +| `codec.none` | stable | Uncompressed; lossless byte-for-byte round-trip. | +| `codec.deflate` | stable | Lossless; level 1-9. | +| `codec.lzw` | stable | Lossless. | +| `codec.packbits` | stable | Lossless. | +| `codec.zstd` | stable | Lossless; level 1-22. | +| `codec.lerc` | experimental | Requires `allow_experimental_codecs=True`. | +| `codec.jpeg2000` | experimental | Requires `allow_experimental_codecs=True`. | +| `codec.j2k` | experimental | Alias for `jpeg2000`; same opt-in. | +| `codec.lz4` | experimental | Requires `allow_experimental_codecs=True`; level 0-16. | +| `codec.jpeg` | internal-only | Requires `allow_internal_only_jpeg=True`. Not externally readable as GeoTIFF. | + +### Readers + +| Key | Tier | Notes | +| --- | --- | --- | +| `reader.local_file` | stable | Local axis-aligned GeoTIFF read; pixel bytes, transform, CRS, and nodata round-trip. | +| `reader.local_cog` | stable | Local COG overview-IFD parsing; CPU path. | +| `reader.fsspec` | advanced | fsspec-backed reads (s3, gcs, and so on). | +| `reader.http` | advanced | Plain HTTP/HTTPS reads; SSRF and private-host filters apply. | +| `reader.http_cog` | advanced | HTTP COG with range-request fetching. The transport surface (redirects, retries) is not yet contracted at the stable bar. | +| `reader.vrt` | advanced | Simple VRT mosaics. Full GDAL VRT parity is out of scope. | +| `reader.sidecar_ovr` | advanced | External `.tif.ovr` sidecar overviews. | +| `reader.allow_rotated` | advanced | Opt-in `allow_rotated=True`; drops the axis-aligned `transform` attr in favour of `rotated_affine`. | +| `reader.allow_unparseable_crs` | advanced | Opt-in escape hatch for CRS strings pyproj cannot parse. | +| `reader.gpu` | experimental | GPU read path; no cross-backend numerical parity claim. | + +### Writers + +| Key | Tier | Notes | +| --- | --- | --- | +| `writer.local_file` | stable | Local GeoTIFF write; round-trips bit-exact under every stable codec. | +| `writer.cog` | stable | CPU writer emits a spec-conforming COG layout (IFD-first, tiled, internal overviews, lossless codec). | +| `writer.overviews` | advanced | Internal overview IFD generation. | +| `writer.bigtiff` | advanced | `bigtiff=True` (or auto-promotion above 4 GiB) writes BigTIFF magic, 8-byte offsets, and 20-byte IFD entries. | +| `writer.bigtiff_cog` | advanced | BigTIFF plus COG. Tracked separately because the combination has its own external-interop surface. | +| `writer.gpu` | experimental | GPU write path. | +| `writer.gdal_metadata_xml` | experimental | `attrs['gdal_metadata_xml']` is escaped before serialisation. | +| `writer.extra_tags` | experimental | Pass-through of TIFF tags outside the structured set via `attrs['extra_tags']`. | + +### Unsupported for this release + +The following combinations are out of contract. They either fail with an +actionable error or are documented as not supported. They will not move into +the table above without a separate epic. + +- Full GDAL VRT parity. `reader.vrt` covers simple mosaics only. +- Warped or reprojection VRTs. Reprojection lives in `xrspatial.reproject`; + the VRT reader does not interpret warp tags. +- Rotated or sheared GeoTIFF *write*. Reads can opt into rotated transforms + (`reader.allow_rotated`), but `to_geotiff` does not yet emit + `ModelTransformationTag`. +- Silent flattening of mixed metadata. Conflicting attrs across stacked + inputs are surfaced rather than collapsed without warning. +- File-like destinations with `cog=True`. The COG writer requires an on-disk + path so the IFD-first layout invariant is checkable. + +## Keeping this page honest + +The tier strings on this page must match `xrspatial.geotiff.SUPPORTED_FEATURES` +at runtime. When a feature is promoted or demoted in `_attrs.py`, this page is +updated in the same PR. The release-gate page +({ref}`reference.geotiff_release_gate`) holds the per-feature regression test +that locks each `stable` promise. + +Parent epic: +[#2340](https://github.com/xarray-contrib/xarray-spatial/issues/2340). diff --git a/docs/source/reference/index.rst b/docs/source/reference/index.rst index 1c207328..867cb021 100644 --- a/docs/source/reference/index.rst +++ b/docs/source/reference/index.rst @@ -15,6 +15,7 @@ Reference flood focal geotiff + geotiff_release_contract geotiff_internals release_gate_geotiff hydrology From 7e4f46d893feefcce51f1d61bfbd23ecf29c0991 Mon Sep 17 00:00:00 2001 From: Brendan Collins Date: Sun, 24 May 2026 04:25:16 -0700 Subject: [PATCH 2/2] Address review: dotted anchor + fail-mode tags on unsupported list (#2347) - Rename the MyST anchor from `reference-geotiff-release-contract` to `reference.geotiff_release_contract` so it matches the dotted naming used by every other reference target in `docs/source/reference/` (e.g. `reference.geotiff`, `reference.geotiff_release_gate`). Update the `:ref:` in `geotiff.rst` accordingly. - Tag each bullet in the "Unsupported for this release" section as either **(fails loudly)** or **(documented-only)** so the fail-loudly-not-partial-work principle from epic #2340 is visible at the bullet level. Quote the literal error string raised by the COG writer for file-like destinations. Disposition of the original review: - Suggestion (anchor naming): fixed. - Nit (per-bullet fail-mode): fixed. - Blockers: none reported. --- docs/source/reference/geotiff.rst | 2 +- .../reference/geotiff_release_contract.md | 37 +++++++++++-------- 2 files changed, 23 insertions(+), 16 deletions(-) diff --git a/docs/source/reference/geotiff.rst b/docs/source/reference/geotiff.rst index 40a3f108..9f372511 100644 --- a/docs/source/reference/geotiff.rst +++ b/docs/source/reference/geotiff.rst @@ -6,7 +6,7 @@ GeoTIFF / COG .. seealso:: - :ref:`reference-geotiff-release-contract` -- the user-facing release + :ref:`reference.geotiff_release_contract` -- the user-facing release contract that defines what each support tier promises and lists every feature in :data:`xrspatial.geotiff.SUPPORTED_FEATURES` against its tier. diff --git a/docs/source/reference/geotiff_release_contract.md b/docs/source/reference/geotiff_release_contract.md index 164ed32e..9440f279 100644 --- a/docs/source/reference/geotiff_release_contract.md +++ b/docs/source/reference/geotiff_release_contract.md @@ -1,4 +1,4 @@ -(reference-geotiff-release-contract)= +(reference.geotiff_release_contract)= # GeoTIFF release contract @@ -109,20 +109,27 @@ category. The `Key` column matches the runtime key. ### Unsupported for this release -The following combinations are out of contract. They either fail with an -actionable error or are documented as not supported. They will not move into -the table above without a separate epic. - -- Full GDAL VRT parity. `reader.vrt` covers simple mosaics only. -- Warped or reprojection VRTs. Reprojection lives in `xrspatial.reproject`; - the VRT reader does not interpret warp tags. -- Rotated or sheared GeoTIFF *write*. Reads can opt into rotated transforms - (`reader.allow_rotated`), but `to_geotiff` does not yet emit - `ModelTransformationTag`. -- Silent flattening of mixed metadata. Conflicting attrs across stacked - inputs are surfaced rather than collapsed without warning. -- File-like destinations with `cog=True`. The COG writer requires an on-disk - path so the IFD-first layout invariant is checkable. +The following combinations are out of contract. Each bullet is tagged +**(fails loudly)** when the call raises an actionable error, or +**(documented-only)** when the call returns without an error but does not +do what a GDAL user might expect. These items will not move into the +table above without a separate epic. + +- **(documented-only)** Full GDAL VRT parity. `reader.vrt` covers simple + mosaics only; unsupported VRT XML elements are ignored rather than + rejected. +- **(documented-only)** Warped or reprojection VRTs. Reprojection lives in + `xrspatial.reproject`; the VRT reader does not interpret warp tags. +- **(fails loudly)** Rotated or sheared GeoTIFF *write*. Reads can opt into + rotated transforms (`reader.allow_rotated`), but `to_geotiff` does not + yet emit `ModelTransformationTag`. +- **(fails loudly)** Silent flattening of mixed metadata. Conflicting + attrs across stacked inputs are surfaced rather than collapsed without + warning. +- **(fails loudly)** File-like destinations with `cog=True`. The COG + writer requires an on-disk path so the IFD-first layout invariant is + checkable; both the eager and GPU writers raise + `"cog=True is not supported for file-like destinations"` up front. ## Keeping this page honest