#781·meetily

fix(recording): make saver startup, drain, and finalization reliable

Author: safvanatzackCreated Sep 7, 2026Updated Sep 7, 2026
Labelsbugbackend

Problem

Three pre-existing failures in the live-recording persistence lifecycle can lose audio or report success after persistence failed. They were identified while reviewing PR #767 and were explicitly deferred because they were neither introduced nor demonstrably amplified by that PR.

These belong together because RecordingSaver owns all three boundaries: storage initialization, queue consumption, and finalization.

1. Auto-save initialization failure silently degrades into total audio loss

RecordingSaver::start_accumulation returns () and only logs when initialize_meeting_folder fails. incremental_saver remains None, but the recording continues and the accumulation task still consumes incoming chunks. With auto_save = true, those chunks cannot be written. At stop, the missing saver is treated as though auto-save had been disabled and returns Ok(None).

Concrete triggers include an unavailable recording directory, permission changes, disk/filesystem errors, and invalid folder state.

Evidence:

2. Stop can discard audio chunks already queued for saving

stop_and_save clears is_saving before the receiver drains. The accumulation task checks that flag immediately after each receive and exits on the next queued chunk, dropping that chunk and everything behind it. The fixed 200 ms sleep does not establish queue completion, and the tokio::spawn handle is not retained or awaited before finalization.

This is timing-dependent: checkpoint I/O only needs to fall behind recording production when Stop is requested.

Evidence:

3. Final save failures are converted into successful shutdown

RecordingSaver::stop_and_save correctly returns errors for audio finalization and final transcript writes. RecordingManager::save_recording_only logs those errors and then returns Ok(()). The command layer therefore enters its success branch, emits recording-shutdown-progress as complete and emits recording-stopped, even when final audio or transcript persistence failed.

Concrete triggers include disk-full, permission changes, disconnected or synchronized folders, and Windows sharing/rename failures.

Evidence:

User impact

  • An entire recording can be discarded despite auto-save being enabled.
  • The saved recording can lose its queued ending audio.
  • Meetily can tell the user that recording stopped successfully when final audio or transcript files are missing or incomplete.
  • The user receives no actionable storage recovery guidance while the only remaining copy may be transient or already dropped.

Required behavior

  1. With auto-save enabled, meeting-folder and incremental-saver initialization must complete before capture starts or the recording is published as live.
  2. Initialization failure must abort startup, roll back constructed recording state/pipeline resources, and surface a storage-specific user-visible error. It must never fall back to discard mode.
  3. Auto-save disabled must retain its current transcript/metadata-only behavior and remain distinguishable from failed initialization.
  4. Stop must prevent new producer sends, close the producer side, drain every chunk already accepted by the saver channel in order, and await saver-task completion before finalizing audio.
  5. Queue completion must be synchronization-based; remove the fixed 200 ms timing assumption and do not use a flag that causes an accepted chunk to terminate draining.
  6. Audio finalization, final transcript write, and metadata completion failures must propagate out of RecordingManager after native resources are safely cleaned up.
  7. Do not emit an unqualified completion/recording-stopped success when persistence failed. Emit a stable partial/failure outcome containing the meeting folder when available and actionable recovery guidance.
  8. Successful recording, auto-save-disabled recording, pause/resume, and transcript persistence behavior must remain unchanged.

Verification

Add deterministic coverage for the observable contracts:

  • Inject meeting-folder/incremental-saver initialization failure with auto-save enabled; startup fails before capture and no audio is silently consumed.
  • Run auto-save disabled through start/stop; transcript/metadata-only completion remains successful.
  • Queue multiple identifiable audio chunks behind a deliberately blocked saver, request Stop, release the saver, and assert every accepted sample reaches finalization exactly once and in order.
  • Inject audio finalization failure, final transcript-write failure, and metadata-completion failure independently; cleanup completes, the caller receives failure/partial status, and no success event is emitted.
  • Confirm a normal recording still emits one successful completion after the saver task drains and final files are verified.

Scope boundaries

  • This issue covers chunks that already reached the recording-saver channel. Upstream capture/resampler/mixer tail draining is tracked separately in #773.
  • Import/retranscription SQLite-to-sidecar reconciliation is tracked separately in #777.
  • PR #767's ONNX loader, lifecycle-phase, tray recovery, and runtime-stage invalidation findings are separate and do not belong in this fix.
  • Do not redesign audio mixing, ASR, or meeting storage formats as part of this work.

Provenance

Source: Zackriya-Solutions/meetily