fix(voice): guard audio attachment after_create_commit hooks on file presence

Both enqueue_audio_transcription and broadcast_message_update_for_audio
fired immediately after Attachment#save without checking whether a file
was actually attached. The broadcast path then walked through
Message#push_event_data → Attachment#audio_metadata → file.metadata,
which is nil when no file is attached, raising NoMethodError on
file.metadata[:width].

This was visible to:
- Captain::OpenAiMessageBuilderService specs that build audio attachments
  without a file (intentional — those specs test attachment_parts logic,
  not file storage). 4 specs failing, all crashing inside the broadcast
  callback rather than in the code under test.
- Any future callsite that creates an audio attachment shell before
  attaching the blob (we don't have one in production today, but the
  callbacks should be defensive).

Add `return unless file.attached?` to both. The transcription job has
nothing to transcribe without a file; the broadcast carries no useful
audio info before the file lands. The callbacks fire again — correctly —
once the blob is attached and committed in a subsequent transaction.
This commit is contained in:
Tanmay Deep Sharma
2026-05-04 14:15:38 +07:00
parent 442631102c
commit 1bcc25f95c
@@ -14,6 +14,7 @@ module Enterprise::Concerns::Attachment
def enqueue_audio_transcription
return unless file_type.to_sym == :audio
return unless file.attached?
Messages::AudioTranscriptionJob.perform_later(id)
end
@@ -21,6 +22,10 @@ module Enterprise::Concerns::Attachment
def broadcast_message_update_for_audio
return unless file_type.to_sym == :audio
return unless message
# Without an attached file, the message serializer's audio_metadata path
# dereferences `file.metadata[:width]` on nil and raises. The pre-attach
# broadcast wouldn't carry useful audio info anyway — skip until upload completes.
return unless file.attached?
message.reload.send_update_event
end