288edd7190
Three vendor-neutral fixes to backend_cuda.cu, each with test coverage: 1. Upload check-order: a cached device tensor is now usable when the caller's host pointers are stale or NULL. CUDA_RELEASE_HOST slots null their host pointers after upload; the current engine reaches those tensors through direct handles (coli_cuda_expert_mlp etc.), but any caller going through coli_cuda_matmul/tensor_upload with a cached tensor — as matmul_qt does for QT tensors — hits the !weights check before the cached-tensor branch and fails spuriously. This hardens the API contract rather than fixing a measured regression; the contract is pinned by a 64x sustained-reuse test. 2. Sticky runtime error (real bug, test-caught): a failed allocation left the last-error state set, so the NEXT healthy launch's cudaGetLastError() check reported 'out of memory' and disabled a perfectly good tensor. cuda_ok() now consumes the error on the failure path; regression-covered. 3. COLI_GPU_FAIL_AFTER=N test hook: every GPU compute entry point (19 total: matmul, expert mlp/group, shared mlp, attention ops, pipe ops) reports failure after N successful calls, so the engine's CPU fallbacks and expert_host_ensure rematerialization can be exercised end-to-end without real hardware faults. Unset = zero effect; uploads/queries are never gated. Validated on GLM-5.2: total failure (N=0) completes coherently with every released expert rematerialized. Tests (run via make cuda-test on any CUDA GPU; vendor-neutral source): 64x sustained matmul reuse after host pointers are freed; upload from a scribbled-and-freed temporary; five graceful upload-failure cases with stats-integrity assertions; healthy-launch-after-failed-alloc (the sticky-error regression); fault-hook on/off restore. Verified on AMD RX 9070 XT via the companion HIP PR's compat header (same test source); a make cuda-test run on NVIDIA hardware would complete the matrix.