Release · v3.14.27
Make the repair script work against a real bucket
fix(storage): make the repair script work against a real bucket
Details
Four faults, every one of them found the first time this ran with a service-role key rather than in review. The script had never been executed. **Object names contain spaces.** `documents/CIKM 2024 Poster.pdf` went into the request line unencoded and http.client refused it outright — the very first object aborted the run. The public URL is now percent-encoded; the copy body still takes the raw key. **Copying an object onto its own key is rejected.** `POST /object/copy` answers `409 KeyAlreadyExists`, so the cheap metadata-only route this script was built on does not exist. Storage offers no metadata-only update at all, so the object is re-uploaded over itself with `x-upsert` — one download and one upload each. **Verification was reading two sources that lie.** The public URL is behind a CDN and this project's public delivery sends `no-cache` whatever the object records, so a served header can never confirm a write. `/object/info/...` is worse: it reported `application/octet-stream` for an object the list endpoint already showed as `application/pdf`, and still did sixty seconds later — which made a successful repair look like a silent no-op and aborted the run a second time. Only the list endpoint's `metadata` tracks a write, so that is what the script now reads, for both the decision and the read-back. **The favicon was being rewritten for nothing.** Python answers `image/vnd.microsoft.icon` where the bucket already served the equivalent `image/x-icon`, so a correct value was being replaced with another correct value — and Storage normalising it back would have tripped the verifier. `.ico` is now pinned to the form already in place. Run against the live bucket: **21 of 21 objects repaired**, re-scan reports 0 remaining. Documents and images now carry `application/pdf`, `image/png`, `image/jpeg` and `max-age=3600` instead of `application/octet-stream` and `no-cache`. A repaired object can still serve its old content-type from a CDN HIT for up to an hour; the origin is correct immediately. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DAJJ63FFnLoD5XLpu6yJaG
Files changed (3)
| backend/supabase_db/DATABASE.md | +21 | −6 |
| backend/supabase_db/scripts/_db_common.py | +6 | −0 |
| backend/supabase_db/scripts/repair_storage_metadata.py | +90 | −53 |