3ffba3f24b
db.service inserted the 'deleted_permanent' feedback row and then deleted the track, but feedback.track_id was ON DELETE CASCADE (verified on the live DB: confdeltype = 'c'), so the audit row deleted itself. feedback contains zero deleted_permanent rows. feedback is an audit log and must outlive its subject: the FK becomes ON DELETE SET NULL. track_id was already nullable, and nothing in backend/ or workers/ SELECTs from feedback — the only other reference is mergeTracks()'s UPDATE feedback SET track_id, which re-points to the survivor — so no caller assumed non-null. Migration 20260730_feedback_track_id_set_null drops the constraint by matching confdeltype rather than by name, since the live schema has drifted. Verified on a scratch PG16: confdeltype flips 'c' -> 'n' and a deleted_permanent row survives its track's deletion. Correct under either resolution of the dislike-lifecycle decision, so it lands independently of it. REVIEW-2026-07-30.md finding 6 (cascade only). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>