QuickCapture silently discards a voice note recorded before the entry is saved #90
Labels
No labels
bug
duplicate
enhancement
future
help wanted
invalid
question
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
rbrooks/TeaLeaves#90
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Severity: High · Confidence: High · Effort: S · Category: ui
Evidence
app/src/components/layout/QuickCapture.tsx:54-63-stop():if (!entryId) { setState(''idle''); resolve(); return; }drops the recording.app/src/components/layout/QuickCapture.tsx:186-savedEntryIdset only afterhandleSavesucceeds; the mic button is reachable before any save.Problem
Opening Quick Capture, tapping the mic, recording, and tapping Stop before saving text throws the recording away with no error, toast, or indication - a natural order ("let me just say what I noticed first").
Impact
Real, silent data loss in the flagship mobile capture flow.
Fix
Short-term: disable the mic until the entry is saved (with an explanatory tooltip). Longer-term: auto-create a draft entry on first Record tap so audio always has a target.
Acceptance criteria
Filed from the 2026-07-15 codebase audit. Full report:
docs/.internal/report-2026-07-15.md(gitignored).Fixed in
4f8e0fe(v7.1.0 wave 4).The bug was broader than filed. It isn't only "record before saving" —
savedEntryIdis set only byhandleSave, which also callssetOpen(false), and the close effect (useEffectonopen) resetssavedEntryIdtonulland callsvoice.reset(). SoentryIdwas alwaysnullwhile the voice panel was open, and every Quick Capture voice note hit theif (!entryId) { setState('idle'); resolve(); }path and vanished. There was no working path at all.That also rules out the suggested short-term fix: disabling the mic until the entry is saved would have disabled it permanently. So I went with the longer-term option:
ensureEntryId()— tapping Record creates the entry first (using the typed content, or a'Voice note'placeholder), so the recorder always has a target by the time Stop runs.handleSaveupdates that entry (PUT /api/entries/:id) instead of creating a duplicate, and a voice-only note can now be saved with no typed text (the Save button no longer requires content once an entry exists; the transcript's "Use as content" still works).'No entry to attach this recording to — nothing was saved.') instead of silently returning to idle — a safety net that should be unreachable.Acceptance criteria:
Verified on the dev server: app build clean, 63/63 app tests, api 238/238. CI green.
One trade-off worth noting: recording then closing without saving now leaves an entry with the
'Voice note'placeholder and the audio attached, rather than discarding the recording. That seemed clearly right for a tool whose first principle is that her data is irreplaceable — but it's easy to revisit.