From b46a0dd0c95637a40762b4550aaed7284ba4bde4 Mon Sep 17 00:00:00 2001 From: Mathias Date: Fri, 2 Oct 2026 17:22:41 +0200 Subject: [PATCH] docs(adr): second review -- the note instead of a refusal, room before spooling, the callable chat model, and the image that was actually built (ADR-035 decision 8) Co-Authored-By: Claude Sonnet 5.5 --- DECISIONS.md | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/DECISIONS.md b/DECISIONS.md index 6013702..1d22f06 100644 --- a/DECISIONS.md +++ b/DECISIONS.md @@ -1735,17 +1735,30 @@ wording while only `content` is merged. `network`, `error`), never its text, which can hold a provider's response body, the spool path or a word from the transcript (`internal/errkind`). The stored reconcile reason and an engine's failure reason are kinds; the page no longer shows provider text. - - **Every local engine call has its own deadline** (`TAPIR_TRANSCRIBE_ENGINE_TIMEOUT`, default 25 - minutes), so a wedged engine fails while the job lives and the fallback can run; the job's own + - **Every local engine call has its own deadline** (`TAPIR_TRANSCRIBE_ENGINE_TIMEOUT`, default 20 + minutes: two wedged engines in sequence then leave 20 of the job's 60 minutes for a fallback), + so a wedged engine fails while the job lives and the fallback can run; the job's own deadline or a cancel still never reaches the cloud. - **The duration limit is checked against what is converted**, not the file's header: ffmpeg is capped at the limit plus a minute, a longer result fails the job (`audio_too_long`), and a result - under 80% of the claimed length and more than two minutes short fails it - (`audio_incomplete`) instead of returning a partial transcript with no warning. - - **The queue is bounded**, 20 waiting in total and 3 per user; a full queue is a 429 with a typed - reason, never a stuck row or a server error. - - **Bad input is a 4xx**: a non-UUID id is a 404, a malformed multipart header is a 400 whose text is - not logged, and a title or file name with control bytes or invalid UTF-8 is cleaned, not a 500. + under 80% of the claimed length and more than two minutes short is **transcribed and noted** on + the audio step ("the audio is 20 min long; the file claimed 1 h 19 min"), not refused. The second + adversarial review showed a complete variable-bitrate MP3 whose header over-estimated its length + by 4x was wrongly refused by the first version of this check; a note keeps a truncated file + visible without turning away real recordings. + - **The queue is bounded**, 20 waiting in total and 3 per user, and its room is checked before the + upload is spooled (not after 200 MB and an ffprobe run); a full queue is a 429 with a typed reason, + never a stuck row or a server error. + - **The configured upload chat model is callable.** It is added to the shared chat service's model + list when uploads are on and it is local, because the service re-maps a model it does not offer + (a valid `iguana/gemma4-31b` was being silently swapped for `koala/phi4-mini`). + - **Bad input is a 4xx**: a non-UUID id is a 404, a malformed or cut-off multipart body is a 400 + whose text is not logged, and a title with control bytes, bidirectional controls or invalid UTF-8 is + cleaned (emoji joiners, Swedish letters and variation selectors are kept), not a 500. + - **The image was built and inspected** (buildah on koala, 2026-10-02): the first build FAILED + (`tar: xz: Cannot exec`, the golang image has no xz); fixed, rebuilt at 180 MB, ffmpeg and ffprobe + run as `nonroot` in distroless. CI does not build the image on a pull request + (`if: github.event_name != 'pull_request'`), so the first CI build of it is the merge to main. Not done, filed as follow-ups: a vendored ffmpeg tarball, CSRF cookie review, ffprobe CPU and stream-count limits, mov external references, `alive_at` clock skew, a hung database blocking the tracker, an unbounded gateway response body, a user-facing notice for a recording that is partial but