From f673d16361195d64728dbb243c3b8e64ea615950 Mon Sep 17 00:00:00 2001 From: Brendan Collins Date: Sat, 18 Jul 2026 12:01:20 -0400 Subject: [PATCH 1/4] Add Examples and fix cross-correlation wording in edge_detection docstrings (#3674) --- xrspatial/edge_detection.py | 116 ++++++++++++++++++++++++- xrspatial/tests/test_edge_detection.py | 46 ++++++++++ 2 files changed, 158 insertions(+), 4 deletions(-) diff --git a/xrspatial/edge_detection.py b/xrspatial/edge_detection.py index e908800f7..2e598b05f 100644 --- a/xrspatial/edge_detection.py +++ b/xrspatial/edge_detection.py @@ -31,12 +31,16 @@ def sobel_x(agg, name='sobel_x', boundary='nan'): """Compute the horizontal gradient of a raster using the Sobel operator. - Detects vertical edges by convolving with the Sobel-X kernel:: + Detects vertical edges by cross-correlating with the Sobel-X kernel:: [[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]] + The kernel is applied by cross-correlation, as in + ``scipy.ndimage.correlate``, so the response is positive where values + increase toward higher column index. + Parameters ---------- agg : xarray.DataArray @@ -50,6 +54,25 @@ def sobel_x(agg, name='sobel_x', boundary='nan'): ------- xarray.DataArray Horizontal gradient with the same shape and backend as the input. + + Examples + -------- + .. sourcecode:: python + + >>> import numpy as np + >>> import xarray as xr + >>> from xrspatial import sobel_x + >>> data = np.array([ + ... [0., 1., 2., 3.], + ... [0., 1., 2., 3.], + ... [0., 1., 2., 3.], + ... [0., 1., 2., 3.]]) + >>> raster = xr.DataArray(data, dims=['y', 'x']) + >>> sobel_x(raster).data + array([[nan, nan, nan, nan], + [nan, 8., 8., nan], + [nan, 8., 8., nan], + [nan, nan, nan, nan]]) """ _validate_raster(agg, func_name='sobel_x', name='agg') out = convolve_2d(agg.data, SOBEL_X, boundary) @@ -60,12 +83,16 @@ def sobel_x(agg, name='sobel_x', boundary='nan'): def sobel_y(agg, name='sobel_y', boundary='nan'): """Compute the vertical gradient of a raster using the Sobel operator. - Detects horizontal edges by convolving with the Sobel-Y kernel:: + Detects horizontal edges by cross-correlating with the Sobel-Y kernel:: [[-1, -2, -1], [ 0, 0, 0], [ 1, 2, 1]] + The kernel is applied by cross-correlation, as in + ``scipy.ndimage.correlate``, so the response is positive where values + increase toward higher row index. + Parameters ---------- agg : xarray.DataArray @@ -79,6 +106,25 @@ def sobel_y(agg, name='sobel_y', boundary='nan'): ------- xarray.DataArray Vertical gradient with the same shape and backend as the input. + + Examples + -------- + .. sourcecode:: python + + >>> import numpy as np + >>> import xarray as xr + >>> from xrspatial import sobel_y + >>> data = np.array([ + ... [0., 0., 0., 0.], + ... [1., 1., 1., 1.], + ... [2., 2., 2., 2.], + ... [3., 3., 3., 3.]]) + >>> raster = xr.DataArray(data, dims=['y', 'x']) + >>> sobel_y(raster).data + array([[nan, nan, nan, nan], + [nan, 8., 8., nan], + [nan, 8., 8., nan], + [nan, nan, nan, nan]]) """ _validate_raster(agg, func_name='sobel_y', name='agg') out = convolve_2d(agg.data, SOBEL_Y, boundary) @@ -108,6 +154,22 @@ def laplacian(agg, name='laplacian', boundary='nan'): ------- xarray.DataArray Laplacian response with the same shape and backend as the input. + + Examples + -------- + .. sourcecode:: python + + >>> import numpy as np + >>> import xarray as xr + >>> from xrspatial import laplacian + >>> data = np.zeros((4, 4)) + >>> data[1, 1] = 1. + >>> raster = xr.DataArray(data, dims=['y', 'x']) + >>> laplacian(raster).data + array([[nan, nan, nan, nan], + [nan, -4., 1., nan], + [nan, 1., 0., nan], + [nan, nan, nan, nan]]) """ _validate_raster(agg, func_name='laplacian', name='agg') out = convolve_2d(agg.data, LAPLACIAN_KERNEL, boundary) @@ -118,12 +180,16 @@ def laplacian(agg, name='laplacian', boundary='nan'): def prewitt_x(agg, name='prewitt_x', boundary='nan'): """Compute the horizontal gradient of a raster using the Prewitt operator. - Detects vertical edges by convolving with the Prewitt-X kernel:: + Detects vertical edges by cross-correlating with the Prewitt-X kernel:: [[-1, 0, 1], [-1, 0, 1], [-1, 0, 1]] + The kernel is applied by cross-correlation, as in + ``scipy.ndimage.correlate``, so the response is positive where values + increase toward higher column index. + Parameters ---------- agg : xarray.DataArray @@ -137,6 +203,25 @@ def prewitt_x(agg, name='prewitt_x', boundary='nan'): ------- xarray.DataArray Horizontal gradient with the same shape and backend as the input. + + Examples + -------- + .. sourcecode:: python + + >>> import numpy as np + >>> import xarray as xr + >>> from xrspatial import prewitt_x + >>> data = np.array([ + ... [0., 1., 2., 3.], + ... [0., 1., 2., 3.], + ... [0., 1., 2., 3.], + ... [0., 1., 2., 3.]]) + >>> raster = xr.DataArray(data, dims=['y', 'x']) + >>> prewitt_x(raster).data + array([[nan, nan, nan, nan], + [nan, 6., 6., nan], + [nan, 6., 6., nan], + [nan, nan, nan, nan]]) """ _validate_raster(agg, func_name='prewitt_x', name='agg') out = convolve_2d(agg.data, PREWITT_X, boundary) @@ -147,12 +232,16 @@ def prewitt_x(agg, name='prewitt_x', boundary='nan'): def prewitt_y(agg, name='prewitt_y', boundary='nan'): """Compute the vertical gradient of a raster using the Prewitt operator. - Detects horizontal edges by convolving with the Prewitt-Y kernel:: + Detects horizontal edges by cross-correlating with the Prewitt-Y kernel:: [[-1, -1, -1], [ 0, 0, 0], [ 1, 1, 1]] + The kernel is applied by cross-correlation, as in + ``scipy.ndimage.correlate``, so the response is positive where values + increase toward higher row index. + Parameters ---------- agg : xarray.DataArray @@ -166,6 +255,25 @@ def prewitt_y(agg, name='prewitt_y', boundary='nan'): ------- xarray.DataArray Vertical gradient with the same shape and backend as the input. + + Examples + -------- + .. sourcecode:: python + + >>> import numpy as np + >>> import xarray as xr + >>> from xrspatial import prewitt_y + >>> data = np.array([ + ... [0., 0., 0., 0.], + ... [1., 1., 1., 1.], + ... [2., 2., 2., 2.], + ... [3., 3., 3., 3.]]) + >>> raster = xr.DataArray(data, dims=['y', 'x']) + >>> prewitt_y(raster).data + array([[nan, nan, nan, nan], + [nan, 6., 6., nan], + [nan, 6., 6., nan], + [nan, nan, nan, nan]]) """ _validate_raster(agg, func_name='prewitt_y', name='agg') out = convolve_2d(agg.data, PREWITT_Y, boundary) diff --git a/xrspatial/tests/test_edge_detection.py b/xrspatial/tests/test_edge_detection.py index a73e1285f..1810ad229 100644 --- a/xrspatial/tests/test_edge_detection.py +++ b/xrspatial/tests/test_edge_detection.py @@ -1,3 +1,6 @@ +import inspect +import re + import numpy as np import pytest import xarray as xr @@ -241,6 +244,49 @@ def test_boundary_modes(self, func): assert_boundary_mode_correctness(np_agg, da_agg, func) +# --------------------------------------------------------------------------- +# Docstring contract +# --------------------------------------------------------------------------- + +class TestDocstrings: + @pytest.mark.parametrize('func', [sobel_x, sobel_y, laplacian, prewitt_x, prewitt_y]) + def test_docstring_params_match_signature(self, func): + # Every parameter documented in the "Parameters" section must exist + # in the signature (and vice versa, in the same order). + sig_params = list(inspect.signature(func).parameters) + doc = inspect.getdoc(func) + lines = doc.splitlines() + start = next(i for i, ln in enumerate(lines) if ln.strip() == 'Parameters') + documented = [] + for ln in lines[start + 2:]: + if ln.strip() in ('Returns', 'References', 'Notes', 'Examples'): + break + m = re.match(r'^(\w+)\s*:', ln) + if m: + documented.append(m.group(1)) + assert documented == sig_params, ( + f'{func.__name__}: documented params {documented} != ' + f'signature params {sig_params}' + ) + + @pytest.mark.parametrize('func', [sobel_x, sobel_y, laplacian, prewitt_x, prewitt_y]) + def test_docstring_has_examples_section(self, func): + doc = inspect.getdoc(func) + assert any(ln.strip() == 'Examples' for ln in doc.splitlines()), ( + f'{func.__name__} docstring has no Examples section' + ) + + @pytest.mark.parametrize('func', [sobel_x, sobel_y, prewitt_x, prewitt_y]) + def test_docstring_states_cross_correlation(self, func): + # convolve_2d applies kernels by cross-correlation, which for the + # antisymmetric Sobel/Prewitt kernels differs from convolution by + # sign. The docstrings used to say "convolving", which predicts the + # negated result. Pin the wording so it does not come back. + doc = inspect.getdoc(func) + assert 'cross-correlat' in doc + assert 'by convolving' not in doc + + # --------------------------------------------------------------------------- # Dask backend # --------------------------------------------------------------------------- From 257c2cec6c307f6fda034f23f4b216e116cd7d49 Mon Sep 17 00:00:00 2001 From: Brendan Collins Date: Sat, 18 Jul 2026 12:01:41 -0400 Subject: [PATCH 2/4] Update documentation sweep state for edge_detection (#3674) --- .claude/sweep-documentation-state.csv | 1 + 1 file changed, 1 insertion(+) diff --git a/.claude/sweep-documentation-state.csv b/.claude/sweep-documentation-state.csv index 54ca71480..608b0fcbc 100644 --- a/.claude/sweep-documentation-state.csv +++ b/.claude/sweep-documentation-state.csv @@ -2,6 +2,7 @@ module,last_inspected,issue,severity_max,categories_found,notes,doc_coverage bump,2026-07-02,#3606,MEDIUM,2;5,"height_func Parameters description gave a per-point f(x,y) contract; actual call is height_func(locations) with a (count,2) array returning a length-count heights array (TypeError on literal use). count typed int with no default; actually Optional, defaults to min(w*h//10, 10_000_000). Docstring plot example executes clean (numpy). Fixed both in PR. LOW-only: no Raises section for MemoryError/ValueError (left documented). CUDA available; cupy/dask+cupy example paths n/a (single .. plot:: is numpy).",1/1 classify,2026-06-25,3506,MEDIUM,1;3,"Cat3: reclassify (numpy/dask/cupy blocks) + equal_interval example outputs were stale/wrong, binary used np.nan in array repr; corrected to actual output (tests confirm code is correct). Cat1: added missing Examples to std_mean, head_tail_breaks, percentiles, maximum_breaks, box_plot. Fixed in deep-sweep-documentation-classify-2026-06-25 (PR for #3506). Cat2 natural_breaks num_sample-None omission already tracked in #3501 (left alone). All 10 public funcs listed in reference/classification.rst (no Cat4 gap). CUDA available: ran numpy examples; cupy/dask reprs reviewed statically.",10/10 convolution,2026-07-02,,MEDIUM,1;3;5,"Deep-sweep 2026-07-02 (deep-sweep-documentation-convolution). Public API per reference/focal.rst 'Focal Statistics': convolution_2d, annulus_kernel, calc_cellsize, circle_kernel, custom_kernel (via xrspatial.focal); convolve_2d listed in metadata public_funcs but not in any reference page. Cat1 MEDIUM: custom_kernel had a one-line stub (added Parameters/Returns/Examples); convolve_2d had NO docstring (added numpydoc). Cat5 MEDIUM: convolution_2d agg backend line omitted Dask+CuPy (code dispatches _convolve_2d_dask_cupy) and had typos 'to processed'/'CuPybacked' -> fixed to name all 4 backends. Cat3 MEDIUM: annulus_kernel example print used comma-array format + stray trailing ')' (real print output has no commas/paren) -> corrected to measured output; convolution_2d dask .compute() example claimed dtype=float32 but np.ones input stays float64 -> removed label; cupy type repr 'cupy.core.core.ndarray' -> 'cupy.ndarray'. Cat3 LOW (fixed in review follow-up): calc_cellsize km example wrote output line as '>>> (1000.0, 1000.0)' (stray prompt on an output line) -> removed the prompt to match the other two output lines in the same example. Cat2/Cat4 clean: params match signatures; all 5 reference-listed funcs present, no stale/dup entries. Verified: numpy+dask+cupy examples executed (CUDA available on host, cupy example ran), values match; test_convolution.py 6 pass; flake8 unchanged (1 pre-existing F401 not_implemented_func baseline).",6/6 +edge_detection,2026-07-18,3674,MEDIUM,1;5,Cat1: all 5 public funcs lacked Examples sections (0 >>> blocks in module); added executed examples. Cat5: gradient docstrings said 'convolving with' kernel but convolve_2d cross-correlates; antisymmetric Sobel/Prewitt kernels flip sign (measured: sobel_x=+8 vs convolve=-8 on left-right ramp); reworded + sign convention + pinned test. Cat5 NaN-propagation gap found here too but fixed by sibling error-handling PR #3678 (Notes sections); scoped out to avoid conflicting edits. Cat2 clean (params/order/defaults match). Cat4 clean (all 5 in reference/focal.rst). Backend claim verified on numpy/cupy/dask+numpy/dask+cupy (CUDA host). LOW unfixed: no module-level docstring; int->float32 promotion undocumented (no wrong claim).,5/5 fire,2026-06-25,,MEDIUM,1;5,"all 7 public funcs (dnbr, rdnbr, burn_severity_class, fireline_intensity, flame_length, rate_of_spread, kbdi) lacked Examples section (Cat1 MEDIUM) and backend-support note (Cat5 MEDIUM); fixed in deep-sweep-documentation-fire-2026-06-25-01; repo issues disabled so no issue number; examples run and outputs match numpy backend; all 7 listed in reference/fire.rst; no Cat2/Cat3/Cat4 issues",7/7 flood,2026-06-25,,HIGH,1;4;5,"Cat4 HIGH: vegetation_roughness, vegetation_curve_number, flood_depth_vegetation public but absent from reference/flood.rst; Cat1 MEDIUM: no Examples on any of 7 public funcs; Cat5 MEDIUM: backend support undocumented (all 4 backends) + NaN propagation undocumented for curve_number_runoff/travel_time. Fixed in deep-sweep-documentation-flood-2026-06-25: added 3 rst entries, Examples+backend Notes to all 7 funcs (examples executed OK on CUDA host), NaN notes. PR #3502 opened with the fix; gh issue create blocked by auto-mode classifier so no issue number.",7/7 geotiff,2026-07-02,,LOW,5,"Re-audit 2026-07-02 (deep-sweep-documentation-geotiff): prior #3592 PAM-sidecar doc fix confirmed merged (HEAD 8ecf14d9). Public surface = open_geotiff, to_geotiff (both re-exported at top level). Cat1 clean: both have full numpydoc Parameters/Returns/Notes/Examples (to_geotiff also Raises); module __doc__ present. Cat2 clean: programmatic inspect.signature vs Parameters diff = 0 for both (28/28 open_geotiff, 24/24 to_geotiff params; no phantom params, no default drift -- sentinel defaults for deprecated aliases documented as such). Cat3 clean: doctest examples are copy-paste-safe +SKIP blocks, pytest --doctest-modules on __init__.py + eager.py = 2 passed 0 fail; rst examples are non-executed code-block:: python. Cat4 clean: both funcs in reference/geotiff.rst autosummary, no dupes/stale entries; SUPPORTED_FEATURES + all referenced error classes (MixedBandMetadataError, PixelSafetyLimitError, CloudSizeLimitError, VRTStableSourcesOnlyError) import OK. Cat5 clean: Returns backend claim (NumPy/Dask/CuPy/Dask+CuPy) matches gpu/chunks dispatch. LOW (not fixed, no /rockout per MEDIUM+ gate): 8 docstrings incl. both public funcs cite docs/source/reference/geotiff_release_contract.rst but the page exists only as .md; open_geotiff hedges 'once that page lands' (intentional fwd-ref), to_geotiff/_writers/_backends cite it plainly. Literal code-span, not a Sphinx xref, so no build break. CUDA available on host.",2/2 From 90592c27b2ead247863e949f0ff3f0f1d9ab255e Mon Sep 17 00:00:00 2001 From: Brendan Collins Date: Sat, 18 Jul 2026 12:04:20 -0400 Subject: [PATCH 3/4] Address review: dedupe cross-correlation wording, note laplacian symmetry (#3674) --- xrspatial/edge_detection.py | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/xrspatial/edge_detection.py b/xrspatial/edge_detection.py index 2e598b05f..4c9d30c63 100644 --- a/xrspatial/edge_detection.py +++ b/xrspatial/edge_detection.py @@ -37,9 +37,8 @@ def sobel_x(agg, name='sobel_x', boundary='nan'): [-2, 0, 2], [-1, 0, 1]] - The kernel is applied by cross-correlation, as in - ``scipy.ndimage.correlate``, so the response is positive where values - increase toward higher column index. + This matches ``scipy.ndimage.correlate``: the response is positive + where values increase toward higher column index. Parameters ---------- @@ -89,9 +88,8 @@ def sobel_y(agg, name='sobel_y', boundary='nan'): [ 0, 0, 0], [ 1, 2, 1]] - The kernel is applied by cross-correlation, as in - ``scipy.ndimage.correlate``, so the response is positive where values - increase toward higher row index. + This matches ``scipy.ndimage.correlate``: the response is positive + where values increase toward higher row index. Parameters ---------- @@ -141,6 +139,8 @@ def laplacian(agg, name='laplacian', boundary='nan'): [ 1, -4, 1], [ 0, 1, 0]] + The kernel is symmetric, so cross-correlation and convolution agree. + Parameters ---------- agg : xarray.DataArray @@ -186,9 +186,8 @@ def prewitt_x(agg, name='prewitt_x', boundary='nan'): [-1, 0, 1], [-1, 0, 1]] - The kernel is applied by cross-correlation, as in - ``scipy.ndimage.correlate``, so the response is positive where values - increase toward higher column index. + This matches ``scipy.ndimage.correlate``: the response is positive + where values increase toward higher column index. Parameters ---------- @@ -238,9 +237,8 @@ def prewitt_y(agg, name='prewitt_y', boundary='nan'): [ 0, 0, 0], [ 1, 1, 1]] - The kernel is applied by cross-correlation, as in - ``scipy.ndimage.correlate``, so the response is positive where values - increase toward higher row index. + This matches ``scipy.ndimage.correlate``: the response is positive + where values increase toward higher row index. Parameters ---------- From 8f7260f1ce110894a5a562966877cef3d688efd0 Mon Sep 17 00:00:00 2001 From: Brendan Collins Date: Sun, 19 Jul 2026 12:53:30 -0400 Subject: [PATCH 4/4] Refresh edge_detection sweep note after #3686 merge (#3674) --- .claude/sweep-documentation-state.csv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.claude/sweep-documentation-state.csv b/.claude/sweep-documentation-state.csv index 608b0fcbc..b72ec9f31 100644 --- a/.claude/sweep-documentation-state.csv +++ b/.claude/sweep-documentation-state.csv @@ -2,7 +2,7 @@ module,last_inspected,issue,severity_max,categories_found,notes,doc_coverage bump,2026-07-02,#3606,MEDIUM,2;5,"height_func Parameters description gave a per-point f(x,y) contract; actual call is height_func(locations) with a (count,2) array returning a length-count heights array (TypeError on literal use). count typed int with no default; actually Optional, defaults to min(w*h//10, 10_000_000). Docstring plot example executes clean (numpy). Fixed both in PR. LOW-only: no Raises section for MemoryError/ValueError (left documented). CUDA available; cupy/dask+cupy example paths n/a (single .. plot:: is numpy).",1/1 classify,2026-06-25,3506,MEDIUM,1;3,"Cat3: reclassify (numpy/dask/cupy blocks) + equal_interval example outputs were stale/wrong, binary used np.nan in array repr; corrected to actual output (tests confirm code is correct). Cat1: added missing Examples to std_mean, head_tail_breaks, percentiles, maximum_breaks, box_plot. Fixed in deep-sweep-documentation-classify-2026-06-25 (PR for #3506). Cat2 natural_breaks num_sample-None omission already tracked in #3501 (left alone). All 10 public funcs listed in reference/classification.rst (no Cat4 gap). CUDA available: ran numpy examples; cupy/dask reprs reviewed statically.",10/10 convolution,2026-07-02,,MEDIUM,1;3;5,"Deep-sweep 2026-07-02 (deep-sweep-documentation-convolution). Public API per reference/focal.rst 'Focal Statistics': convolution_2d, annulus_kernel, calc_cellsize, circle_kernel, custom_kernel (via xrspatial.focal); convolve_2d listed in metadata public_funcs but not in any reference page. Cat1 MEDIUM: custom_kernel had a one-line stub (added Parameters/Returns/Examples); convolve_2d had NO docstring (added numpydoc). Cat5 MEDIUM: convolution_2d agg backend line omitted Dask+CuPy (code dispatches _convolve_2d_dask_cupy) and had typos 'to processed'/'CuPybacked' -> fixed to name all 4 backends. Cat3 MEDIUM: annulus_kernel example print used comma-array format + stray trailing ')' (real print output has no commas/paren) -> corrected to measured output; convolution_2d dask .compute() example claimed dtype=float32 but np.ones input stays float64 -> removed label; cupy type repr 'cupy.core.core.ndarray' -> 'cupy.ndarray'. Cat3 LOW (fixed in review follow-up): calc_cellsize km example wrote output line as '>>> (1000.0, 1000.0)' (stray prompt on an output line) -> removed the prompt to match the other two output lines in the same example. Cat2/Cat4 clean: params match signatures; all 5 reference-listed funcs present, no stale/dup entries. Verified: numpy+dask+cupy examples executed (CUDA available on host, cupy example ran), values match; test_convolution.py 6 pass; flake8 unchanged (1 pre-existing F401 not_implemented_func baseline).",6/6 -edge_detection,2026-07-18,3674,MEDIUM,1;5,Cat1: all 5 public funcs lacked Examples sections (0 >>> blocks in module); added executed examples. Cat5: gradient docstrings said 'convolving with' kernel but convolve_2d cross-correlates; antisymmetric Sobel/Prewitt kernels flip sign (measured: sobel_x=+8 vs convolve=-8 on left-right ramp); reworded + sign convention + pinned test. Cat5 NaN-propagation gap found here too but fixed by sibling error-handling PR #3678 (Notes sections); scoped out to avoid conflicting edits. Cat2 clean (params/order/defaults match). Cat4 clean (all 5 in reference/focal.rst). Backend claim verified on numpy/cupy/dask+numpy/dask+cupy (CUDA host). LOW unfixed: no module-level docstring; int->float32 promotion undocumented (no wrong claim).,5/5 +edge_detection,2026-07-18,3674,MEDIUM,1;5,"Cat1: all 5 public funcs lacked Examples sections (0 >>> blocks in module); added executed examples. Cat5: gradient docstrings said 'convolving with' kernel but convolve_2d cross-correlates; antisymmetric Sobel/Prewitt kernels flip sign (measured: sobel_x=+8 vs convolve=-8 on left-right ramp); reworded + sign convention + pinned test. Cat5 NaN-propagation gap found here too but fixed by sibling error-handling PR #3678 (Notes sections); scoped out to avoid conflicting edits. Cat2 clean (params/order/defaults match). Cat4 clean (all 5 in reference/focal.rst). Backend claim verified on numpy/cupy/dask+numpy/dask+cupy (CUDA host). LOW unfixed: no module-level docstring. Former LOW int-promotion doc gap resolved by security PR #3686 (wide ints now promote to float64, documented in Returns; merged into this branch).",5/5 fire,2026-06-25,,MEDIUM,1;5,"all 7 public funcs (dnbr, rdnbr, burn_severity_class, fireline_intensity, flame_length, rate_of_spread, kbdi) lacked Examples section (Cat1 MEDIUM) and backend-support note (Cat5 MEDIUM); fixed in deep-sweep-documentation-fire-2026-06-25-01; repo issues disabled so no issue number; examples run and outputs match numpy backend; all 7 listed in reference/fire.rst; no Cat2/Cat3/Cat4 issues",7/7 flood,2026-06-25,,HIGH,1;4;5,"Cat4 HIGH: vegetation_roughness, vegetation_curve_number, flood_depth_vegetation public but absent from reference/flood.rst; Cat1 MEDIUM: no Examples on any of 7 public funcs; Cat5 MEDIUM: backend support undocumented (all 4 backends) + NaN propagation undocumented for curve_number_runoff/travel_time. Fixed in deep-sweep-documentation-flood-2026-06-25: added 3 rst entries, Examples+backend Notes to all 7 funcs (examples executed OK on CUDA host), NaN notes. PR #3502 opened with the fix; gh issue create blocked by auto-mode classifier so no issue number.",7/7 geotiff,2026-07-02,,LOW,5,"Re-audit 2026-07-02 (deep-sweep-documentation-geotiff): prior #3592 PAM-sidecar doc fix confirmed merged (HEAD 8ecf14d9). Public surface = open_geotiff, to_geotiff (both re-exported at top level). Cat1 clean: both have full numpydoc Parameters/Returns/Notes/Examples (to_geotiff also Raises); module __doc__ present. Cat2 clean: programmatic inspect.signature vs Parameters diff = 0 for both (28/28 open_geotiff, 24/24 to_geotiff params; no phantom params, no default drift -- sentinel defaults for deprecated aliases documented as such). Cat3 clean: doctest examples are copy-paste-safe +SKIP blocks, pytest --doctest-modules on __init__.py + eager.py = 2 passed 0 fail; rst examples are non-executed code-block:: python. Cat4 clean: both funcs in reference/geotiff.rst autosummary, no dupes/stale entries; SUPPORTED_FEATURES + all referenced error classes (MixedBandMetadataError, PixelSafetyLimitError, CloudSizeLimitError, VRTStableSourcesOnlyError) import OK. Cat5 clean: Returns backend claim (NumPy/Dask/CuPy/Dask+CuPy) matches gpu/chunks dispatch. LOW (not fixed, no /rockout per MEDIUM+ gate): 8 docstrings incl. both public funcs cite docs/source/reference/geotiff_release_contract.rst but the page exists only as .md; open_geotiff hedges 'once that page lands' (intentional fwd-ref), to_geotiff/_writers/_backends cite it plainly. Literal code-span, not a Sphinx xref, so no build break. CUDA available on host.",2/2