V204: storage location-truth, the schema half (phase 3 of
dev_docs/plans/2026-09-22-storage-libraries.md).
From this version on, where a file's bytes are is what its
phoenix_kit_file_locations rows say, not what trying every enabled
bucket by key finds. Two rules make those rows trustworthy:
- One row per instance per bucket (G7). Duplicate rows are removed,
keeping the oldest of each
(file_instance_uuid, bucket_uuid), andphoenix_kit_file_locations_instance_bucket_indexmakes the pair unique from now on.phoenix_kit_file_locations_path_indexis what a read looks a key's buckets up by. - A bucket that still holds files cannot be deleted (G4). The
location's bucket FK moves from
ON DELETE CASCADE(deleting a bucket quietly dropped its rows and left its objects behind) toON DELETE RESTRICT.
phoenix_kit_file_location_checks records which instances have been
checked against every bucket, and how many held them; the instances that
already had location rows are marked checked here (their writer recorded
every bucket it wrote).
Nothing that reads bytes runs here. The other instances (Tessera tiles and
comment attachments stored before every writer recorded its locations)
are checked by Storage.Workers.LocationBackfillJob, which the application queues on
boot while any are left, and which probes each bucket once per instance.
Locks
The dedupe is one DELETE. The unique index is a plain build (the chain's
convention, see V193), so writes to phoenix_kit_file_locations wait while
it builds. The FK is replaced NOT VALID → validate → swap, each step its
own statement (V203's replace_constraint/7).
Re-runnable.
Summary
Functions
Rolls V204 back: drops the unique index and puts the bucket FK back to
ON DELETE CASCADE. Removed duplicate rows are not restored (they
described the same object twice).