Follow-up from the #401 review (the PR merged while the review was being finalised, so filing the two release-blocking findings as an issue instead).
1. Any meeting longer than ~13 minutes fails against the default endpoint
_run_openai_asr uploads the whole preprocessed WAV in one request. _preprocess_audio outputs 16 kHz mono pcm_s16le (~32 KB/s), and OpenAI's documented upload limit is 25 MB - so a recording over roughly 13 minutes gets HTTP 413 from api.openai.com (Groq's limit is similar). Meetings are the primary use case and most run longer than that, so as shipped the engine works for short tests and fails for real usage. Chunking exists only in the Parakeet path.
Options, cheapest first:
- (a) compress the upload with the bundled ffmpeg (64 kbps mono MP3 is ~52 min per 25 MB - still not a 2h meeting);
- (b) reuse the windowing approach to send chunks and stitch segments - this would also restore a per-chunk
HEARTBEAT so a slow request can't trip the inactivity watchdog;
- (c) at minimum, a preflight size check whose error names the limit.
(b) is the real fix; (c) is the floor.
2. Unvalidated 200 responses can silently destroy a meeting
Responses are trusted without schema validation, and the failure mode is silent data loss rather than an error:
- A 200 whose JSON lacks
text (error envelope from a proxy/shim) yields an empty result indistinguishable from real silence: the pipeline writes the silence sentinel, "succeeds", and - with Save recordings off - deletes the only audio.
- In the
text fallback, a 200 HTML page (captive portal, misconfigured base URL) becomes the transcript verbatim.
Fix: require the expected fields (text key actually present, not defaulted), reject non-JSON/error-shaped bodies with a raised error so the honest transcription_failed path preserves the audio.
Also worth picking up (from the same review)
getTranscriptionEnv() injects STENOAI_OAI_API_KEY into every transcription subprocess once a key is stored, even when a local engine is active (the comment claims otherwise). Gate on the configured engine.
_do_request embeds the first 500 bytes of HTTP error bodies verbatim in raised errors, which propagate into renderer-visible errors, processing.log, and failure-note frontmatter - a provider/proxy that echoes request headers would persist the Bearer key. Redact token-shaped content.
set_openai_asr_api_url accepts plain http:// silently (key + audio cleartext). Require https except loopback, or warn explicitly.
- Response negotiation is
verbose_json → text only; OpenAI's gpt-4o-transcribe family accepts only json, so today's flagship STT model fails both passes. No retry on 429/5xx either. Consider verbose_json → json → text + a small bounded retry.
verbose_json returns language as a full name ("english"), which resolve_output_language passes through verbatim where the pipeline expects an ISO code. Normalize, or fall back to the existing text-based detection.
- A stray empty
config.json.lock was committed to the repo root in da1fd68.
Full review context with the praise it deserves (the safeStorage key handling is exemplary): see the #401 thread.
Follow-up from the #401 review (the PR merged while the review was being finalised, so filing the two release-blocking findings as an issue instead).
1. Any meeting longer than ~13 minutes fails against the default endpoint
_run_openai_asruploads the whole preprocessed WAV in one request._preprocess_audiooutputs 16 kHz mono pcm_s16le (~32 KB/s), and OpenAI's documented upload limit is 25 MB - so a recording over roughly 13 minutes gets HTTP 413 fromapi.openai.com(Groq's limit is similar). Meetings are the primary use case and most run longer than that, so as shipped the engine works for short tests and fails for real usage. Chunking exists only in the Parakeet path.Options, cheapest first:
HEARTBEATso a slow request can't trip the inactivity watchdog;(b) is the real fix; (c) is the floor.
2. Unvalidated 200 responses can silently destroy a meeting
Responses are trusted without schema validation, and the failure mode is silent data loss rather than an error:
text(error envelope from a proxy/shim) yields an empty result indistinguishable from real silence: the pipeline writes the silence sentinel, "succeeds", and - with Save recordings off - deletes the only audio.textfallback, a 200 HTML page (captive portal, misconfigured base URL) becomes the transcript verbatim.Fix: require the expected fields (
textkey actually present, not defaulted), reject non-JSON/error-shaped bodies with a raised error so the honesttranscription_failedpath preserves the audio.Also worth picking up (from the same review)
getTranscriptionEnv()injectsSTENOAI_OAI_API_KEYinto every transcription subprocess once a key is stored, even when a local engine is active (the comment claims otherwise). Gate on the configured engine._do_requestembeds the first 500 bytes of HTTP error bodies verbatim in raised errors, which propagate into renderer-visible errors,processing.log, and failure-note frontmatter - a provider/proxy that echoes request headers would persist the Bearer key. Redact token-shaped content.set_openai_asr_api_urlaccepts plainhttp://silently (key + audio cleartext). Require https except loopback, or warn explicitly.verbose_json → textonly; OpenAI'sgpt-4o-transcribefamily accepts onlyjson, so today's flagship STT model fails both passes. No retry on 429/5xx either. Considerverbose_json → json → text+ a small bounded retry.verbose_jsonreturnslanguageas a full name ("english"), whichresolve_output_languagepasses through verbatim where the pipeline expects an ISO code. Normalize, or fall back to the existing text-based detection.config.json.lockwas committed to the repo root inda1fd68.Full review context with the praise it deserves (the safeStorage key handling is exemplary): see the #401 thread.