M1-15: Keep the unfinalised transcript tail #40
No reviewers
Labels
No labels
area/agent
area/capture
area/editor
area/geo
area/security
area/sync
area/transcription
area/ui
area/vault
area/voice-memos
blocked
milestone/M1
milestone/M2
milestone/M3
milestone/M4
needs-decision
needs-hardware
p0
p1
p2
type/bug
type/enhancement
type/feature
type/idea
type/infrastructure
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Stash/stash-ios!40
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "m1-15-volatile-tail"
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?
Closes #25.
What it does
A force-quit measured on device cost the last 16 seconds of speech of a 210-second memo: the
speech engine was holding them, and the drain that recovers them happens at stop, which a crash
never reaches.
The engine's outstanding phrases now go to
<base>_transcription.volatile.vttinside thecapture's existing
.partsfolder, rewritten atomically at most every two seconds against amonotonic clock. Every finalised cue supersedes them. A normal stop deletes the file unread; the
launch sweep appends them to a recovered transcript, marked as never confirmed, and only for the
stretch after the last finalised cue.
Why two speech modules
The short version of this change adds
.volatileResultsto the transcriber the app already hasand keeps filtering on
isFinal. It is wrong in a way that does not show up in testing: Appledocuments that a hypothesis is not guaranteed to be reissued as final, so a phrase delivered once
as a guess would be dropped by that filter — from an ordinary recording that stopped cleanly. That
version would have cost speech from every capture in order to save it from the rare crashed one.
So the analyzer runs two transcriber modules over the one input sequence. The transcript's module
is configured exactly as before and remains the only source of
TranscriptCue. Apple recommendsthis split for exactly this case.
How a guess is kept out of the transcript
VolatileTailis a different type fromTranscriptCue, so the parts writer, the boundary ruleand the cue list on screen will not take one. Checked by the compiler on every build.
rewrites the file the moment a cue catches up with one. Order-independent, so it cannot be raced.
directory is in the Files app, and this path publishes into somebody's transcript.
The provisional cues carry the identifier
unconfirmedas well as aNOTEblock, because aconforming parser drops comments and a person reading the file does not read identifiers.
Validated
coexist on real hardware, and a normal stop still produces the transcript it should.
Not validated
What the second recogniser costs over a long recording. A 20-minute locked-screen capture is
still to be tested, and battery and heat are what it answers. If the cost threatens a multi-hour
memo, closing the issue is the right response rather than tuning it — the recording is worth more
than its tail.
Also open, and the reason the launch diagnostic now reports when a recovered capture ended in
unconfirmed words: how much speech the tail actually recovers in practice, across more than the
one force-quit that produced the 16-second measurement.
Codex
Four passes, dispositions in
.agent/m1-15-volatile-tail/SUMMARY.md. The two that changed theshape of this:
several can be outstanding — which would have recovered about three seconds of the sixteen and
reported nothing missing.
One finding rejected: the test review wanted
TranscriptRecovery.runexercised directly, whichneeds the app's real documents directory and the recorder singleton and so is not a logic-only
test. Its body delegates to
recover, which is tested.Documentation
AGENTS.md's "Do not ask for volatile results" is replaced by the narrower rule this establishes.The decision record is in
stash-docs, in a separate commit — see the note on the PR there.