diff --git a/docs/use-cases/audio_upload.feature b/docs/use-cases/audio_upload.feature new file mode 100644 index 0000000..4665a37 --- /dev/null +++ b/docs/use-cases/audio_upload.feature @@ -0,0 +1,101 @@ +Feature: Upload an audio recording, get a private Swedish transcript, discuss it + As someone with a recorded meeting on my computer + I want to upload it and then ask questions about what was said + So that I can find out what was decided, what is open and who owes what + + # ADR-033, tapir#33. The load-bearing constraint: an uploaded transcript is + # PRIVATE content, so it lives in its own RLS-scoped store and never in the + # shared public-caption `transcripts` table (ADR-021). Rejection is synchronous, + # the audio is never retained, and a failed job ends in a terminal state with a + # message — never a spinner (ADR-025). Audio only: video is #28. + + Background: + Given I am a registered user with audio upload enabled + + Scenario: The upload form states the limits up front + When I open the upload page + Then I see the size limit and the length limit before I choose a file + + Scenario: An accepted recording is queued and I am taken to its page + When I upload an audio file within the limits + Then it is recorded as queued for me + And I am redirected to its page + + Scenario: A recording with no title is named after its file + When I upload an audio file and give no title + Then its title is the filename without its extension + + Scenario: A file containing video is rejected, naming issue 28 + When I upload a file that has a video track + Then it is rejected with a message that video is tracked in issue 28 + And nothing is recorded + + Scenario: A recording over the length limit is rejected with both lengths + When I upload a recording longer than the limit + Then it is rejected stating the recording's length and the limit + And nothing is recorded + + Scenario: A file over the size limit is rejected as too large + When I upload a file larger than the size limit + Then it is rejected with 413 and a message about the limit + And nothing is recorded + + Scenario: An audio-only MP4 is not mistaken for video + When I upload an mp4 container that has an audio stream and no video stream + Then it is accepted + And an mp3 whose only video stream is cover art is accepted too + + Scenario: A file that is not media is rejected as unreadable + When I upload a file ffprobe cannot read + Then it is rejected as the file's fault + + Scenario: A broken ffprobe is reported as our fault, not as a bad file + When the prober itself fails + Then the upload is an error rather than a rejection of my file + + Scenario: A recording becomes a transcript and the audio is deleted + Given I have uploaded a recording + When it has been transcribed + Then the transcript is stored privately for me + And the audio is deleted + + Scenario: The endpoint that served a transcript is recorded and shown + Given a recording was transcribed by the fallback endpoint + When I view its page + Then it names the fallback endpoint, because that means the audio left the homelab + + Scenario: The local endpoint is tried first and the fallback only on failure + When the primary transcription endpoint fails for any reason + Then the fallback endpoint transcribes it + But when the primary succeeds the fallback is never contacted + + Scenario: A failed transcription ends in a message, never a spinner + When every transcription endpoint fails + Then the upload is failed with a typed reason + And its page shows that reason and stops polling + + Scenario: A restart fails the jobs it interrupted + Given the service restarted while a recording was queued or transcribing + When it starts again + Then those uploads are failed as interrupted + And any audio left in the spool is deleted + + Scenario: Only one recording is transcribed at a time + When several recordings are queued + Then they are transcribed one after another + + Scenario: My uploads are invisible to other users + Given another user has uploaded a recording + When I ask for it by its id + Then I get 404 and no part of its title or text + And the chat for it calls no model + + Scenario: I can ask about my recording and get a grounded answer + Given my recording has been transcribed + When I ask a question about it + Then the answer comes from my transcript through the same chat as a video's + + Scenario: A long recording is not cut to its first third + Given my recording's transcript is longer than the caption default + When I ask a question about it + Then the transcript is sent with the upload budget, not the 18,000-character caption default