M2-01: Read a memo's transcript on the phone #41

Merged
wk merged 1 commit from m2-01-transcript-detail into main 2026-08-09 13:54:00 -04:00
Member

Closes #27.

Tapping a memo pushes a detail screen that reads <base>_transcription.vtt off disk and shows its
cues with their timestamps. Read-only — there is no editor, and nothing this screen reads is ever
written back.

What it does

  • The cues, with a timestamp beside each line, selectable so a line can be copied out.
  • A transcript the app knows is missing speech says so before the words. The signal is a transcript
    part left behind, not the .parts folder existing — the folder also survives when somebody has
    put a file of their own into it, and keying on that would raise the missing-speech warning on
    captures that are missing nothing.
  • Words recovered from a crash that the speech engine never confirmed are marked as unconfirmed.
    The file has said so since M1-15; nothing read it until now.
  • No transcript is four different answers, not one: nobody spoke or no speech model; the recording
    died and has not been assembled; the file is there and will not open, with a message saying which
    and what to do; or the memo is no longer in the folder at all.

The reader

The app has written WebVTT since M1-09 and only ever parsed it back for the crash tail. That parser
stays strict — it decides whether unconfirmed words may be published into a transcript, and it
refuses a whole file over one bad byte. The new one puts a file on screen, so it fails the other
way: it tolerates what a file that has been through the Files app looks like and shows every cue it
can, counting the blocks it cannot and putting that number on screen. The two do not merge, and the
reasoning is in stash-docs: Two readers for one file format.

Validated

  • make test — 275 tests, 25 suites, green. make lint clean.
  • Simulator, with synthetic files pushed into the container and the app relaunched so nothing was
    held in memory: a transcript reading back with its escapes decoded, the unconfirmed marker on a
    recovered tail, and the missing-speech banner on a capture with a part left behind.
  • On the device: a real memo's transcript reading back.

Not validated: the no-transcript, unassembled and unreadable presentations were never seen on
screen. macOS withdrew scripted clicking partway through the simulator pass, so those paths are
covered by TranscriptReading and its tests rather than by looking at them. There is no UI test
target, so nothing automated covers the row tap or the destination either.

Codex

Four passes in .agent/m2-01-transcript-detail/, no critical or high findings in any of them. Two
were real bugs: a cue whose identifier began with STYLE was dropped silently, and a crafted file
of newlines could exhaust memory when opened. Every disposition, including the six rejections and
their reasons, is in SUMMARY.md.

🤖 Generated with Claude Code

Closes #27. Tapping a memo pushes a detail screen that reads `<base>_transcription.vtt` off disk and shows its cues with their timestamps. Read-only — there is no editor, and nothing this screen reads is ever written back. ## What it does - The cues, with a timestamp beside each line, selectable so a line can be copied out. - A transcript the app knows is missing speech says so before the words. The signal is a transcript part left behind, not the `.parts` folder existing — the folder also survives when somebody has put a file of their own into it, and keying on that would raise the missing-speech warning on captures that are missing nothing. - Words recovered from a crash that the speech engine never confirmed are marked as unconfirmed. The file has said so since M1-15; nothing read it until now. - No transcript is four different answers, not one: nobody spoke or no speech model; the recording died and has not been assembled; the file is there and will not open, with a message saying which and what to do; or the memo is no longer in the folder at all. ## The reader The app has written WebVTT since M1-09 and only ever parsed it back for the crash tail. That parser stays strict — it decides whether unconfirmed words may be published into a transcript, and it refuses a whole file over one bad byte. The new one puts a file on screen, so it fails the other way: it tolerates what a file that has been through the Files app looks like and shows every cue it can, counting the blocks it cannot and putting that number on screen. The two do not merge, and the reasoning is in `stash-docs`: *Two readers for one file format*. ## Validated - `make test` — 275 tests, 25 suites, green. `make lint` clean. - Simulator, with synthetic files pushed into the container and the app relaunched so nothing was held in memory: a transcript reading back with its escapes decoded, the unconfirmed marker on a recovered tail, and the missing-speech banner on a capture with a part left behind. - On the device: a real memo's transcript reading back. **Not validated:** the no-transcript, unassembled and unreadable presentations were never seen on screen. macOS withdrew scripted clicking partway through the simulator pass, so those paths are covered by `TranscriptReading` and its tests rather than by looking at them. There is no UI test target, so nothing automated covers the row tap or the destination either. ## Codex Four passes in `.agent/m2-01-transcript-detail/`, no critical or high findings in any of them. Two were real bugs: a cue whose identifier began with `STYLE` was dropped silently, and a crafted file of newlines could exhaust memory when opened. Every disposition, including the six rejections and their reasons, is in `SUMMARY.md`. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Tapping a memo pushes a detail screen that reads the .vtt beside the audio and
shows its cues with their timestamps. Read-only.

The substance is a lenient WebVTT reader, kept separate from the strict one that
recovers a crash's unconfirmed tail: that one publishes into somebody's
transcript and fails closed, this one puts a file on screen and shows every cue
it can, counting the blocks it cannot. Nothing it produces is written back.

A transcript the app knows is missing speech says so, keyed on a transcript part
left behind rather than on the parts folder — the folder also survives when
somebody has put a file of their own into it. Words recovered from a crash that
the engine never confirmed are marked. A memo with no transcript says which of
the ordinary reasons it is rather than showing a blank screen.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
wk merged commit afb3e52467 into main 2026-08-09 13:54:00 -04:00
wk deleted branch m2-01-transcript-detail 2026-08-09 13:54:00 -04:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Stash/stash-ios!41
No description provided.