fix(storage): surface per-object bulk deletion failures
DeleteWithPrefix ignored DeleteObjectsOutput.Errors, so an S3 HTTP 200 response with failed objects was treated as a successful deletion. Callers could then remove the associated volume metadata while objects remained. S3 returns per-object errors in quiet mode too.
Return the existing nil, error result when any object fails, including the first failed key, bucket, code and message. Record a batch's deleted names only after the request and per-object results succeed. Merge current main and resolve the test-import conflict while preserving its pagination, partial-result and Tigris behavior.
Validation on macOS arm64 with Go 1.25.8:
- Five table cases use the real AWS SDK with an in-memory HTTP transport: quiet success across pages, quiet object failure, mixed results, a later-page failure and a request-level failure. They check submitted keys, quiet mode and fail-fast pagination.
- On current main (
b5bf561), the three per-object failure cases fail and both controls pass. All five cases pass with the fix. - Eleven existing pure unit tests (93 subcases) pass. The combined 12 tests (98 subcases) also pass with
-race. go vet ./pkg/clients, gofmt andgit diff --checkpass. Independent static review found no required changes; an independent dynamic rerun was not completed.
No listener or real S3/Redis integration was used; the full client package suite was not run. AI assistance was used for implementation and local review.
Summary by cubic
DeleteWithPrefix previously ignored S3's per-object deletion errors, so an HTTP 200 with failed objects was treated as a successful deletion and callers could remove volume metadata while objects remained.
The method now returns an error when any object fails, reporting the first failed key, bucket, code, and message. Deleted names are only recorded after both the request and per-object results succeed; pagination and request-error handling are unchanged.
Adds table-driven tests using the real AWS SDK with an in-memory transport, covering quiet success across pages, per-object failures, mixed results, later-page failures, and request-level failures.