Context
The tooling from #937 and #939 is implemented on branch array-api-strict-triage-tooling (mwcraig fork, commit 94ca9ec):
CCDPROC_ARRAY_LIBRARY=array-api-strict test backend with fixture arrays placed on the non-default Device("device1"), so any implicit conversion to numpy raises — the same failure signal as CuPy's device-to-host error, with no GPU needed. Includes a py313-strict tox env and CI job.
- Escape-site dedupe report (
CCDPROC_TRIAGE_ESCAPES=1): groups test failures by the innermost non-test ccdproc frame.
backend_xfail / backend_skip markers applied per backend; documented limitations (astroscrappy, scipy.ndimage.median_filter, reproject, block_reduce/block_replicate) are now xfailed under array-api-strict.
- Escape logger (
CCDPROC_LOG_ARRAY_ESCAPES=1): warns when np.asarray/np.asanyarray/np.ma.asanyarray receive a non-numpy array-API array, catching backends that convert silently (dask, JAX).
Results
Full suite under CCDPROC_ARRAY_LIBRARY=array-api-strict: 139 failed / 192 passed / 5 skipped. After marking documented limitations: 109 failed / 30 xfailed. As predicted in #939, the dedupe report collapses the failures to about ten distinct escape sites.
Escape-site → root-cause mapping
| Escape site |
Failures |
Root cause |
Tracked in |
combiner.py:189 Combiner.__init__ |
44 |
Stacks per-image arrays by building a nested Array; array-api-strict rejects this ("Use stack instead"). Likely also the biggest CuPy failure source. |
no existing issue |
_ccddata_wrapper_for_array_api.py:74 _arithmetic_wrapper |
11 |
Device-mismatch / dtype coercion inside the CCDData arithmetic wrapper |
possibly related to #927 |
| combiner scaling tests |
~9 |
Quantity leaking into array-API arithmetic (TypeError: Expected Array or Python scalar) |
#936 |
test_ccdproc.py:174 test_subtract_overscan |
6 |
numpy-only .copy() method called on an Array |
no existing issue |
core.py:862 subtract_dark |
4 |
unit-mismatch/device issue |
no existing issue |
core.py:611 subtract_overscan (via ccd_process) |
4 |
median fallback doesn't handle namespaces without median/allclose |
#906 |
core.py:1459 rebin |
4 |
numpy-only coordinates.astype("i") method instead of xp.astype(...) |
no existing issue |
core.py:459 create_deviation |
~2 |
bool-dtype handling in __mul__ |
no existing issue |
core.py:1233 sigma_func + gain/deviation singletons |
~4 |
densification / device mismatch via astropy.stats |
#929 |
test_image_collection.py, test_ccdproc_logging.py:75, misc singletons |
~4 |
test-suite code using raw numpy (np.zeros_like) on foreign-device arrays; an ImageFileCollection gap |
no existing issue (partly test-only) |
Xfailed as documented limitations (30 tests): astroscrappy (cosmicray_lacosmic, 21), scipy.ndimage.median_filter (cosmicray_median, 7 — overlaps #935), reproject (wcs_project, 4 — see #930/#940), block_reduce/block_replicate (3 — see #940).
Suggested next steps
Follow-up to #909, #937, #939. Counts from a 2026-07-06 run on the branch above.
🤖 Generated with Claude Code
https://claude.ai/code/session_01Qri8rDgkWjCT7Yb7QKJrhf
Context
The tooling from #937 and #939 is implemented on branch
array-api-strict-triage-tooling(mwcraig fork, commit 94ca9ec):CCDPROC_ARRAY_LIBRARY=array-api-stricttest backend with fixture arrays placed on the non-defaultDevice("device1"), so any implicit conversion to numpy raises — the same failure signal as CuPy's device-to-host error, with no GPU needed. Includes apy313-stricttox env and CI job.CCDPROC_TRIAGE_ESCAPES=1): groups test failures by the innermost non-test ccdproc frame.backend_xfail/backend_skipmarkers applied per backend; documented limitations (astroscrappy,scipy.ndimage.median_filter, reproject,block_reduce/block_replicate) are now xfailed under array-api-strict.CCDPROC_LOG_ARRAY_ESCAPES=1): warns whennp.asarray/np.asanyarray/np.ma.asanyarrayreceive a non-numpy array-API array, catching backends that convert silently (dask, JAX).Results
Full suite under
CCDPROC_ARRAY_LIBRARY=array-api-strict: 139 failed / 192 passed / 5 skipped. After marking documented limitations: 109 failed / 30 xfailed. As predicted in #939, the dedupe report collapses the failures to about ten distinct escape sites.Escape-site → root-cause mapping
combiner.py:189Combiner.__init___ccddata_wrapper_for_array_api.py:74_arithmetic_wrapperQuantityleaking into array-API arithmetic (TypeError: Expected Array or Python scalar)test_ccdproc.py:174test_subtract_overscan.copy()method called on an Arraycore.py:862subtract_darkcore.py:611subtract_overscan(viaccd_process)median/allclosecore.py:1459rebincoordinates.astype("i")method instead ofxp.astype(...)core.py:459create_deviation__mul__core.py:1233sigma_func+ gain/deviation singletonsastropy.statstest_image_collection.py,test_ccdproc_logging.py:75, misc singletonsnp.zeros_like) on foreign-device arrays; anImageFileCollectiongapXfailed as documented limitations (30 tests): astroscrappy (
cosmicray_lacosmic, 21),scipy.ndimage.median_filter(cosmicray_median, 7 — overlaps #935),reproject(wcs_project, 4 — see #930/#940),block_reduce/block_replicate(3 — see #940).Suggested next steps
Combiner.__init__nested-array stacking alone accounts for 44 of 109 failures and looks like a one-linexp.stackfix).sparse(Add sparse test backend as a densification detector (and eventual supported library) #938) is wired up the same way, failures reproducing under both proxies can be treated as confirmed CuPy bugs per the CuPy issues #909 strategy.Follow-up to #909, #937, #939. Counts from a 2026-07-06 run on the branch above.
🤖 Generated with Claude Code
https://claude.ai/code/session_01Qri8rDgkWjCT7Yb7QKJrhf