[Backend] Warn and show a countdown before retention deletes a failed transcription's only audio copy #402
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Severity: HIGH
Found in the August 2026 session lifecycle review (#319).
A session whose transcription failed has its only surviving audio — the raw recording itself, since no transcript was ever produced — permanently deleted by the default retention policy after 7 days, with no notification sent to the GM and no way for the GM to even see the countdown before it happens on the page where they'd notice it.
Evidence
webapp/backend/app/services/settings_service.py:129(_DEFAULT_AUDIO_RETENTION_DAYS = 7) combined with the default modeAUDIO_RETENTION_DELETE_AFTER_PROCESSING(:89) — this is the out-of-the-box policy for every new instance/campaign that doesn't override it.webapp/backend/app/tasks/reminder_tasks.py:2678-2712(enforce_retention, pass 2) — fordelete_after_processingmode, this pass only ever reaches a session that failed processing (a successful run's audio is already deleted inline byapply_post_processing_audio_retentionat the moment it succeeds). The anchor for a failed run issession.updated_at(:2705-2707), so it's swept on the same 7-day window as everything else — a debug grace period, not a deliberate retention decision for a failed job's only copy.webapp/backend/app/routers/admin.py:88-93— thepermanent_deletion_atcomputation that would let someone see a countdown exists only on the admin recordings endpoint; there is no equivalent surfaced on the GM-facing session page.permanent_deletion_ator a "your audio will be deleted" message anywhere inreminder_tasks.py.Failure scenario
A hosted tenant's Whisper endpoint is briefly misconfigured. Friday's session fails transcription (
audio_processing_status = 'failed'), and the GM — heading into a week off — doesn't notice. Day 8 rolls around:enforce_retentionsweeps the failed session's audio directory because it's the only artifact still on disk and the 7-day clock has expired. The recording is gone. Since transcription never succeeded, no transcript exists either — the entire session is unrecoverable, with no warning ever sent.Proposed fix
Never delete a failed-processing session's audio without first delivering a notification to the GM (Discord DM or in-app) with a clear countdown, and surface
permanent_deletion_aton the session detail page itself (not just the admin console) once a session is failed and its clock has started. Consider also lengthening the default window specifically for the failed case (distinct from the successful-and-approved case, where deletion is intentional and low-risk) since a failed run's audio is the only copy of anything for that session.Acceptance criteria
permanent_deletion_atfor any session with audio pending deletion.delete_after_processingwindow (or otherwise deliberately widened), since it guards the only remaining copy of the recording.Partially addressed by #427 (
d4881b9onfix/v4.0.1-retention-safety) — noting the change in shape, not claiming this is done.The "countdown" half now exists for free. Previously a
failedtranscription's audio was deleted directly by the retention sweep when its window expired: no trash state, noaudio_trashed_at, so nothing for the Admin recordings page to computepermanent_deletion_atfrom. There was no countdown to show because there was no interval to count down.#427 made every retention mode reach deletion through the trash. So an expiring window on a failed session now:
audio_processing_status = trashedand stampsaudio_trashed_at,permanent_deletion_at,So the GM gets both a visible countdown and considerably more time — a failed session's only audio copy now survives
retention_window + 7 daysinstead of vanishing on a Beat tick.Still outstanding: the "warn" half. Nothing proactively tells the GM. They have to go and look at the Admin page. If the intent is a notification — a Discord message, an email, a dashboard banner when a failed session is approaching permanent deletion — that is untouched and is the substantive remainder of this issue.
Worth rescoping the title/body to just the warning, since the countdown part is no longer missing.
Merged in PR #458 (CI green). Closing.
Acceptance criteria:
permanent_deletion_at, not just the admin recordings list.The one criterion resolved differently from the issue text
The issue asks for the failed case to be "independently configurable from the general
delete_after_processingwindow (or otherwise deliberately widened)". #427 already did the widening: every mode reaches deletion through the trash, with a 7-day grace floored in code rather than defaulted, so a failed session's audio survivesretention_window + 7 days. The issue's premise — that it "vanishes on a Beat tick" — was true when it was filed and is no longer.A separate knob was rejected rather than forgotten: more retention settings means more ways to misconfigure the one artefact in this system that cannot be regenerated. Agreed with you before building.
Worth knowing for future retention work
permanent_deletion_atwas computed inline in the admin router while the sweeper derived the same boundary from the opposite direction. Rather than add a third copy in the warning task, it moved toapp/retention.pyand all three now read it — a countdown that disagrees with the sweep is worse than no countdown, because it gets believed.Two details that are load-bearing rather than incidental:
Mutation-checked both guards independently. 1,470 backend, 457 frontend, 220 bot tests pass.