GeoTIFF release gate / audit checklist#
Note
This page is the audit trail for the GeoTIFF promises that release notes are allowed to make. Every promised tier below points to at least one regression test that locks the behaviour. If a row is missing a test, the release notes cannot promise that tier.
The tier strings come from xrspatial.geotiff.SUPPORTED_FEATURES.
stable means the contract is gated by CI and a regression breaks the
build. advanced means the feature is tested and works but the surface
may shift before a 1.0 release. experimental means the feature is
covered but not promised; behaviour can change without a deprecation
window. internal_only means the feature exists for one specific
internal use case and is not part of the public surface.
Each row also names the epic that owns the row so a reviewer can trace
any acceptance statement back to the issue that defined it: #2286
(COG promotion), #2321 (VRT contract and release hardening),
#2340 (feature tiering), #2341 (correctness and backend parity),
#2342 (conservative VRT subset), and #2344 (remote / source
safety hardening). The doc-readiness epic that owns this checklist
itself is #2345.
How a maintainer runs this gate#
This section is the operational entry point for the release review. Walk it once per release-tag candidate before signing off.
Selecting the gate suite#
Every regression test cited in the rows below lives under
xrspatial/geotiff/tests/. The gate is the union of those files. The
shortest invocation is:
pytest xrspatial/geotiff/tests/
To run only the release-gate-tagged subset that backs this checklist, use
the release_gate marker. Every gate test lives under a single registry
file (xrspatial/geotiff/tests/release_gates/test_stable_features.py)
so the selector picks the registry up exactly:
pytest xrspatial/geotiff/tests/release_gates/ -m release_gate
The -m release_gate selector also works from the wider tests root and
returns the same set of tests.
GPU rows live behind the standard CUDA fixtures. They auto-skip when
cupy or a CUDA device is unavailable, so the same command runs on a
CPU-only host. The GPU rows are tagged experimental; their skip is not
a release blocker (see the decision rule below).
The cross-cutting meta-gates (the consolidated
xrspatial/geotiff/tests/release_gates/test_stable_features.py plus
xrspatial/geotiff/tests/release_gates/test_features.py) are part of the same suite.
They fail if a row in this checklist names a feature key that is missing
from xrspatial.geotiff.SUPPORTED_FEATURES or a test file that
does not exist.
Handling skipped rows#
A skipped row is not the same as a passing row. Before signing off:
Confirm the skip reason is one of: GPU not present, optional codec library not installed (
codec.lerc,codec.jpeg2000,codec.j2k,codec.lz4), or the COG validator opt-in (XRSPATIAL_REQUIRE_COG_VALIDATOR=1) is intentionally off in this environment.Anything skipped for a reason other than the three above is a blocker. Treat
ImportError,ModuleNotFoundError, or environment-error skips inside the gate suite as failures unless the row is already taggedexperimental.The
xfailrows inside theNegative casessection ofrelease_gates/test_stable_features.pyare intentional pins for follow-up work (see the in-file section docstring). A newly-passingxfailis also a signal: the linked follow-up has landed, the row should be re-tiered in this PR, and thexfailmarker on the test should be removed in the same commit so the gate cannot silently regress.
Promote / demote decision rule#
Use this rule to decide what to do with a row after the gate suite runs:
All rows for a tier pass and the row’s acceptance statement still matches the implementation: keep the tier. No edit required.
A row currently at
stableregresses (the cited test fails on a freshmain-tracking checkout): the release is blocked. Either fix the regression in this release or demote the row toadvancedand updatexrspatial.geotiff.SUPPORTED_FEATURESin the same PR. Astablerow cannot ship red.A row at
advancedregresses: the release is not blocked, but the row is demoted toexperimentalin the same PR. Release notes cannot keep promisingadvancedwhile the regression is open.A row at
experimentalregresses: note it in the release summary; no tier change is required.experimentalrows are explicitly not release-blocking.A row at
experimentaloradvancedhas been green for a full release cycle and the cited test covers every supported backend: it is a promotion candidate. The promotion edit goes in a PR that updates both the row here andxrspatial.geotiff.SUPPORTED_FEATUREStogether; the two cannot drift.
If a row’s acceptance statement no longer matches the test (the test was amended without updating the row), fix the row in this PR before tagging. A row that lies about its own gate is worse than a missing row.
A note on sub-gate rows#
Some rows in the tables below are sub-gates of a broader feature key
(for example reader.http – SSRF defense, or writer.cog –
tile-layout pre-flight). A sub-gate row can carry a stricter tier than
its parent feature row. reader.http is advanced because the
HTTP read surface as a whole still has unresolved questions (redirect
handling, retry policy), but the SSRF fail-closed defense inside it is
a hard gate at stable: SSRF cannot regress, even on an advanced
read path. Sub-gate tier stricter than parent is intentional, not
drift, and does not need to be reconciled in an audit pass.
Cross-references#
Before promoting a feature from
advancedtostable, add a row here and updatexrspatial.geotiff.SUPPORTED_FEATURESin the same PR so the docs and the runtime constant agree.When deprecating or removing a feature, update both the row here and the
SUPPORTED_FEATURESentry in the same PR.The parity gate in
xrspatial/geotiff/tests/release_gates/test_features.pyalready asserts every codec key is tiered; this checklist extends that to the reader / writer / VRT / HTTP / GPU surfaces.
Local GeoTIFF read and write#
Feature |
Tier |
One-line acceptance |
Regression test |
Epic |
|---|---|---|---|---|
|
stable |
Round-trip a local GeoTIFF: pixel bytes, |
|
|
|
stable |
|
|
|
|
stable |
For each representative file, a window strictly interior to the
raster returns the expected shape, coords that are a bit-exact
slice of the unwindowed read, an |
|
|
|
stable |
|
|
|
|
stable |
|
|
|
|
stable |
|
|
|
|
advanced |
Internal overview IFDs round-trip; the reader can pick a level. |
|
|
|
advanced |
|
|
|
|
experimental |
|
|
|
|
experimental |
|
|
|
Codec |
stable |
Lossless byte-for-byte round-trip on integer and float dtypes. |
|
|
Stable codec round-trip (read / write / read) |
stable |
For every stable codec * promised dtype combination, a full write / read / write / read cycle preserves byte-exact pixels (NaN-aware for float) and the canonical release attrs. See the cited test for the codec, dtype, and attr-key matrix. |
|
|
Codec |
experimental |
Rejected by default; accepted with
|
|
|
Codec |
internal_only |
Rejected by default; accepted only with
|
|
Cloud-optimized GeoTIFF (COG)#
Feature |
Tier |
One-line acceptance |
Regression test |
Epic |
|---|---|---|---|---|
|
stable |
|
|
|
|
stable |
Local COG with overview IFDs decodes byte-for-byte through eager and dask paths. |
|
|
|
advanced |
Range-request COG read honours the per-tile byte-count cap and the SSRF / private-host filter. |
|
|
|
advanced |
BigTIFF + COG combination passes the dedicated compliance suite (header magic, IFDs, tile and overview offset tables). |
|
|
|
stable |
Raises |
|
|
|
stable |
Non-positive tile sizes raise |
|
HTTP / fsspec reads#
Feature |
Tier |
One-line acceptance |
Regression test |
Epic |
|---|---|---|---|---|
|
advanced |
|
|
|
|
advanced |
Non-HTTP schemes ( |
|
|
|
stable |
URLs resolving to loopback, link-local, or RFC1918 ranges raise
|
|
|
|
stable |
Tile or strip declared sizes exceeding |
|
|
|
stable |
|
|
Nodata lifecycle#
Feature |
Tier |
One-line acceptance |
Regression test |
Epic |
|---|---|---|---|---|
Nodata round-trip (read -> write) |
stable |
The sentinel survives read and write across every backend; integer
sentinels are preserved bit-exact, float sentinels surface as NaN
only when |
|
|
|
stable |
|
|
|
Mixed-band metadata reject |
stable |
Mixed nodata across bands fails closed unless an explicit opt-in resolves the ambiguity. |
|
|
VRT mixed-band nodata fail-closed |
stable |
VRT sources with conflicting per-band nodata raise rather than silently flatten. |
|
attrs contract#
Feature |
Tier |
One-line acceptance |
Regression test |
Epic |
|---|---|---|---|---|
Contract version stamp |
stable |
Every read stamps |
|
|
Canonical attrs after read |
stable |
|
|
|
Attrs pass-through on write |
stable |
User-supplied attrs survive write round-trips; reserved keys are not silently dropped. |
|
|
|
stable |
|
|
|
|
experimental |
Rotated reads surface |
|
|
|
experimental |
|
|
|
|
experimental |
|
|
|
|
experimental |
|
|
VRT supported subset#
Note
VRT is the advanced tier. It covers simple GDAL VRT mosaics over
GeoTIFF sources with compatible CRS, transform orientation, pixel size,
dtype, and band count. Warped / reprojection VRTs, mixed CRS without an
opt-in, nested VRTs, arbitrary resampling beyond the tested subset, and
complex source / mask / alpha semantics are explicit non-goals (see
#2321, #2342, and the VRT prose in GeoTIFF / COG).
Feature |
Tier |
One-line acceptance |
Regression test |
Epic |
|---|---|---|---|---|
|
advanced |
VRT over compatible GeoTIFF sources returns the same pixels and attrs through eager and dask paths. |
|
|
VRT default |
stable |
Missing source files fail at construction, not at compute. |
|
|
VRT |
advanced |
Holes surface as the band sentinel, |
|
|
VRT source / dest rectangle validation |
stable |
Out-of-bounds source or destination rectangles raise at construction. |
|
|
VRT path containment |
stable |
Relative source paths are constrained to the VRT’s directory tree
and cannot escape via |
|
|
VRT resampling algorithm allow-list |
advanced |
Unsupported resampling identifiers are rejected; supported ones
( |
|
|
VRT dtype / band layout consistency |
stable |
Mixed dtype, mixed band count, or mismatched 12-bit-vs-16-bit sources raise rather than coerce. |
|
|
VRT lazy / chunked read parity |
advanced |
Chunked VRT reads return the same shape, coords, attrs, and values as eager reads on the supported subset. |
|
|
VRT single-parse contract |
stable |
VRT XML is parsed once per read; chunked callers do not re-parse per-chunk. |
|
|
VRT narrow exception surface |
stable |
VRT-specific failures surface as typed exceptions rather than as
generic |
|
|
VRT presence gate |
stable |
At least one regression test exists for every promised VRT behaviour (this row is a meta-gate on the rows above). |
|
|
VRT write ( |
advanced |
Writer rejects source-incompatibility cases at the writer boundary
( |
|
Sidecar and overview interactions#
Feature |
Tier |
One-line acceptance |
Regression test |
Epic |
|---|---|---|---|---|
|
advanced |
External |
|
|
Overview metadata survival (internal COG and |
stable |
For both internal-COG and external |
|
|
Remote sidecar byte order |
stable |
Sidecar |
|
|
Remote sidecar chunked read |
advanced |
Chunked dask reads can resolve remote sidecars without materializing the full file. |
|
|
Sidecar |
stable |
The cloud byte budget applies to sidecar fetches, not just the parent file. |
|
GPU paths (experimental)#
Note
GPU read and write are tagged experimental in
xrspatial.geotiff.SUPPORTED_FEATURES. Behaviour can change
without a deprecation window. The tests below pin the documented
behaviour but a regression here is not a release blocker.
Feature |
Tier |
One-line acceptance |
Regression test |
Epic |
|---|---|---|---|---|
|
experimental |
GPU read returns the same pixels and attrs as the CPU path on the golden corpus where the GPU path is exercised. |
|
|
|
experimental |
GPU read errors emit |
|
|
|
experimental |
GPU write produces a file the CPU reader can decode bit-exact on the supported codec subset. |
|
|
GPU nodata handling |
experimental |
Integer and float nodata sentinels survive the GPU read / write round-trip. |
|
Internal-only surfaces (not promised)#
Feature |
Tier |
One-line acceptance |
Regression test |
Epic |
|---|---|---|---|---|
Codec |
internal_only |
Lossy 8-bit codec retained for one internal use case. Opt-in via
|
|
Cross-cutting CI gates#
These gates are not tier rows but they back the rest of the checklist.
release_gates/test_features.py– every codec in_VALID_COMPRESSIONShas aSUPPORTED_FEATUREStier, and the writer rejects experimental and internal-only codecs without their respective opt-in flags. Owning epic: #2340.parity/test_backend_matrix.pyandparity/test_pixel_equality.py– cross-backend pixel and metadata parity across the 4 read backends (numpy, cupy, dask+numpy, dask+cupy) on the golden corpus. Owning epic: #2341.xrspatial/geotiff/tests/release_gates/test_stable_features.py(Cross-cutting meta-gatessection) – meta-gate that asserts every promised VRT behaviour in this checklist resolves to a real test file and a realSUPPORTED_FEATURESentry. Owning epic: #2321.xrspatial/geotiff/tests/release_gates/test_stable_features.py(Negative casessection) – negative cross-cutting gate. Pins that ambiguous metadata fails closed at every promised read entry point: conflicting CRS between header and.aux.xmlPAM sidecar (xfail until PAM sidecar support lands), integer nodata sentinel that cannot be honoured on a float-promoted raster (xfail against#1774follow-up), rotated transform withoutallow_rotated=Trueuniformly across eager / dask / windowed paths, and mixed-tier VRT children when stable-only is requested (xfail against epic #2342). Owning epic: #2341.
Owning epics#
The release gate rows above point at one of the following epics. Each link resolves on GitHub; the title is kept here so a reader walking the file does not need to leave the page to confirm scope.
#2286 – Promote COG support to ready / stable with compliance and parity gates.
#2321 – GeoTIFF release hardening: define and lock down supported VRT contract.
#2340 – GeoTIFF release contract and feature tiering.
#2341 – GeoTIFF correctness and backend parity release gate.
#2342 – Conservative VRT support contract for GeoTIFF release.
#2344 – GeoTIFF remote / source safety hardening.
#3163 – Register the
unpack/packscale-offset surface inSUPPORTED_FEATURESand the release contract.