Goal
Move COG support from "use with caution" to a clearly documented ready/stable state, starting with a narrow production contract and expanding only when the matching test gates exist.
COG should be split into separate readiness tracks because the risks are different:
- COG writer:
to_geotiff(..., cog=True)
- COG reader: local COG reads
- HTTP/range COG reader: remote COG reads, windowed reads, and dask graph reads
Proposed stable scope for the first promotion
Promote only this subset first:
- Axis-aligned 2D/3D rasters.
- CPU writer and CPU reader paths.
- Stable codecs only:
none, deflate, lzw, zstd, and packbits if current interop coverage supports it.
- Internal overviews only.
- Normal CRS, transform, dtype, nodata, band, and pixel-is-area / pixel-is-point behavior.
Keep these out of the first stable claim:
- GPU COG read/write.
- Experimental codecs:
lerc, jpeg2000 / j2k, lz4.
- Internal-only JPEG.
- Rotated transforms.
- External
.tif.ovr sidecars.
- File-like destinations with
cog=True.
- Any BigTIFF COG behavior not covered by external validation.
Implementation plan
1. Define the COG readiness contract in code and docs
- Split broad feature tiering into more precise entries, e.g.
writer.cog, reader.local_cog, reader.http_cog.
- Keep HTTP/range COG separate from local COG because it has additional transport, range, coalescing, and security behavior.
- Update
SUPPORTED_FEATURES only after test gates are in place.
Relevant files:
xrspatial/geotiff/_attrs.py
docs/source/reference/geotiff.rst
examples/user_guide/52_COG_Overview_Generation.ipynb
2. Add an external COG compliance gate for the writer
For COGs written by to_geotiff(..., cog=True), assert external interoperability, not just xrspatial self-read.
Test matrix should cover:
- Stable codecs.
- Integer and float dtypes.
- Single-band and multiband rasters.
- Nodata sentinel and NaN nodata cases.
- Pixel-is-area and pixel-is-point georeferencing.
- Explicit and auto-generated overview levels.
- Overview resampling modes currently intended to be stable.
Assertions should include:
- Rasterio can open the file.
- Base pixels match expected data.
- Overview count and dimensions match expected levels.
- Overview pixels match expected values or documented tolerances.
- CRS, transform, nodata, dtype, band count, and dims survive.
- TIFF layout is COG-like: tiled layout, overview IFDs, sane tile offsets, IFDs placed before data.
- Optional when available: validate with GDAL/rio-cogeo and skip cleanly when unavailable.
Likely test files:
xrspatial/geotiff/tests/test_cog.py
xrspatial/geotiff/tests/test_golden_corpus_overview_cog_1930.py
- new
xrspatial/geotiff/tests/test_cog_writer_compliance.py
3. Promote local COG writer/read before HTTP COG
Acceptance criteria for local COG readiness:
xrspatial write COG -> xrspatial read passes.
xrspatial write COG -> rasterio read passes.
rasterio/GDAL COG fixture -> xrspatial read passes.
- Stable codec matrix passes.
- Nodata-aware overviews pass for integer and float rasters.
- Overview georef inheritance works.
- Pixel-is-point / pixel-is-area behavior is pinned.
- BigTIFF COG is either covered and promoted or explicitly remains advanced.
After this gate passes, writer.cog and possibly reader.local_cog can be promoted for the scoped contract.
4. Harden HTTP/range COG separately
HTTP COG should become ready only after range behavior is part of the contract.
Acceptance criteria:
- Windowed reads fetch only intersecting tiles/strips.
- Overview reads fetch overview data, not full-resolution data.
band= on multiband planar/interleaved COGs returns correct pixels and avoids unnecessary reads where possible.
- Dask COG reads parse metadata once per graph, not once per chunk task.
- Tests assert range count and total bytes fetched.
- Redirect/private-host/security behavior stays fail-closed.
- Truncated/malformed COGs close HTTP resources reliably.
- Coalescing behavior is bounded and configurable.
Existing relevant tests:
xrspatial/geotiff/tests/test_http_cog_coalesce.py
xrspatial/geotiff/tests/test_cog_http_parallel_decode_2026_05_15.py
xrspatial/geotiff/tests/test_http_range_validation_1735.py
xrspatial/geotiff/tests/test_cog_http_close_on_error_1816.py
xrspatial/geotiff/tests/test_http_window_band_planar_1669.py
xrspatial/geotiff/tests/test_http_stripped_window_max_pixels_issue_A_1842.py
5. Add COG to the parity/release gate
Create a dedicated COG parity file or extend the backend parity suite with a focused COG layer.
Required rows:
xrspatial write COG -> xrspatial eager read
xrspatial write COG -> xrspatial dask read
xrspatial write COG -> rasterio read
golden/rasterio COG fixture -> xrspatial local read
golden/rasterio COG fixture -> xrspatial HTTP range read
golden/rasterio COG fixture -> xrspatial dask HTTP range read
Keep skip reasons explicit and issue-linked. Avoid silent skips for dependency-gated rows.
Relevant existing gate:
xrspatial/geotiff/tests/test_backend_full_parity_2211.py
6. Promote docs and feature tiers last
Only after the gates above pass:
- Move the scoped COG features from advanced to stable.
- Document exactly what is stable.
- Leave unsupported or not-yet-certified combinations marked advanced/experimental.
- Add release notes describing the COG stability contract.
Done when
- The scoped COG writer compliance test passes against rasterio and, where available, GDAL/rio-cogeo.
- Local COG read/write parity is in the release gate.
- HTTP COG range behavior has explicit byte/range assertions or remains advanced.
SUPPORTED_FEATURES reflects the split stable/advanced contract.
- Docs state the stable COG subset and the remaining caveats.
Goal
Move COG support from "use with caution" to a clearly documented ready/stable state, starting with a narrow production contract and expanding only when the matching test gates exist.
COG should be split into separate readiness tracks because the risks are different:
to_geotiff(..., cog=True)Proposed stable scope for the first promotion
Promote only this subset first:
none,deflate,lzw,zstd, andpackbitsif current interop coverage supports it.Keep these out of the first stable claim:
lerc,jpeg2000/j2k,lz4..tif.ovrsidecars.cog=True.Implementation plan
1. Define the COG readiness contract in code and docs
writer.cog,reader.local_cog,reader.http_cog.SUPPORTED_FEATURESonly after test gates are in place.Relevant files:
xrspatial/geotiff/_attrs.pydocs/source/reference/geotiff.rstexamples/user_guide/52_COG_Overview_Generation.ipynb2. Add an external COG compliance gate for the writer
For COGs written by
to_geotiff(..., cog=True), assert external interoperability, not just xrspatial self-read.Test matrix should cover:
Assertions should include:
Likely test files:
xrspatial/geotiff/tests/test_cog.pyxrspatial/geotiff/tests/test_golden_corpus_overview_cog_1930.pyxrspatial/geotiff/tests/test_cog_writer_compliance.py3. Promote local COG writer/read before HTTP COG
Acceptance criteria for local COG readiness:
xrspatial write COG -> xrspatial readpasses.xrspatial write COG -> rasterio readpasses.rasterio/GDAL COG fixture -> xrspatial readpasses.After this gate passes,
writer.cogand possiblyreader.local_cogcan be promoted for the scoped contract.4. Harden HTTP/range COG separately
HTTP COG should become ready only after range behavior is part of the contract.
Acceptance criteria:
band=on multiband planar/interleaved COGs returns correct pixels and avoids unnecessary reads where possible.Existing relevant tests:
xrspatial/geotiff/tests/test_http_cog_coalesce.pyxrspatial/geotiff/tests/test_cog_http_parallel_decode_2026_05_15.pyxrspatial/geotiff/tests/test_http_range_validation_1735.pyxrspatial/geotiff/tests/test_cog_http_close_on_error_1816.pyxrspatial/geotiff/tests/test_http_window_band_planar_1669.pyxrspatial/geotiff/tests/test_http_stripped_window_max_pixels_issue_A_1842.py5. Add COG to the parity/release gate
Create a dedicated COG parity file or extend the backend parity suite with a focused COG layer.
Required rows:
xrspatial write COG -> xrspatial eager readxrspatial write COG -> xrspatial dask readxrspatial write COG -> rasterio readgolden/rasterio COG fixture -> xrspatial local readgolden/rasterio COG fixture -> xrspatial HTTP range readgolden/rasterio COG fixture -> xrspatial dask HTTP range readKeep skip reasons explicit and issue-linked. Avoid silent skips for dependency-gated rows.
Relevant existing gate:
xrspatial/geotiff/tests/test_backend_full_parity_2211.py6. Promote docs and feature tiers last
Only after the gates above pass:
Done when
SUPPORTED_FEATURESreflects the split stable/advanced contract.