Files
bookhoard/internal
John O'Keefe f47734dd7d fix(podcasts): generic media delete refuses episode rows (invariant 2)
The admin endpoint DELETE /api/media-items/:id predated podcasts and
would delete any media row — including podcast episodes — if hit
directly. Invariant 2 (absolute form, user decision 2026-10-30) says
episode rows are removed ONLY by whole-feed removal: "the feed should
match the XML until the entire feed is gone." The plan audit found
this endpoint was the one remaining surface that could violate it:
the poller, unsubscribe, and the admin file-deletion endpoints are
files-only, and the hash-conflict merge can't see episodes (they
never hash).

The guard sits right after the GetMediaItem read and BEFORE the
storage-down check, so a refused episode never touches storage
resolution. Same segregation pattern as the generic edit path
(D9/D10, UpdateMediaItem).

Pinned by TestDeleteMediaItemPodcastGuard: admin DELETE of an episode
→ 409 with the row surviving; a book delete through the same endpoint
→ 204 control.
2026-10-30 14:57:08 -04:00
..