M2-05: A memo is up to three files #32

Closed
opened 2026-08-08 19:56:52 -04:00 by agent · 1 comment
Member

Teach discovery, deletion and the docs about <base>_track.gpx before anything writes one.

Why this lands ahead of the writer

RecordingStore and MemoLibrary currently encode "a memo is two files" — <base>_audio.m4a and
<base>_transcription.vtt. M2-07 introduces a third. Landing the writer first means a build exists
where a track file is on disk and swipe-to-delete strands it, and #12 has already handed the
Documents directory to the user, so a stranded file is one they will see.

M1-10 established the pattern for testing this without the producer: plant files and exercise the
consumer. That is exactly what this issue does.

Scope

  • Deletion removes the track alongside the audio and transcript, under the existing rule that the
    audio goes last and only if nothing else failed — the audio is what puts the row on screen,
    so keeping it keeps the memo visible and the deletion retryable.
  • Discovery is unchanged in its trigger: a memo is a memo because its audio exists. A track with no
    audio beside it is not a memo, the same way a transcript with no audio is not one.
  • README.md and AGENTS.md stop saying "two files and only two". The pair becomes a triple, with
    the third optional, and the rename warning covers it — <base> is what makes three files one
    memo, and renaming any of them breaks it.
  • The .parts targeted-removal rule from #12 extends to whatever the track's part files are named,
    so finalisation still never removes a file it did not write.

Tests

Planted <base>_track.gpx files against RecordingStore and MemoLibrary, synthetic —
no real coordinates in fixtures. This repository is public and a location fixture with real
numbers in it is somebody's house.

Done when

  • Deleting a memo with a track removes all three files.
  • A failed transcript deletion still leaves the audio and the row, unchanged from today.
  • A track file with no audio beside it does not appear as a memo.
  • The docs describe three files.

Milestone 2 of the Stash v3 rebuild. M2 is still app-side — no sync, no account, no server. It
turns a list of memos into something you can open, listen to, read and see the route of. Sync
arrives in M3. There is no milestone/M2 label yet (creating org labels needs owner rights), so
the title carries the milestone.

Working agreement for every issue in this repo: feature branch, tested before the PR opens
(on-device where the label says so), then Wes reviews the PR and we walk the code together. Docs
update in the same commit. A PR that takes more than 20 minutes to review is too big — say so and
split it.

Teach discovery, deletion and the docs about `<base>_track.gpx` **before** anything writes one. ## Why this lands ahead of the writer `RecordingStore` and `MemoLibrary` currently encode "a memo is two files" — `<base>_audio.m4a` and `<base>_transcription.vtt`. M2-07 introduces a third. Landing the writer first means a build exists where a track file is on disk and swipe-to-delete strands it, and #12 has already handed the Documents directory to the user, so a stranded file is one they will see. M1-10 established the pattern for testing this without the producer: plant files and exercise the consumer. That is exactly what this issue does. ## Scope - Deletion removes the track alongside the audio and transcript, under the existing rule that the **audio goes last and only if nothing else failed** — the audio is what puts the row on screen, so keeping it keeps the memo visible and the deletion retryable. - Discovery is unchanged in its trigger: a memo is a memo because its audio exists. A track with no audio beside it is not a memo, the same way a transcript with no audio is not one. - `README.md` and `AGENTS.md` stop saying "two files and only two". The pair becomes a triple, with the third optional, and the rename warning covers it — `<base>` is what makes three files one memo, and renaming any of them breaks it. - The `.parts` targeted-removal rule from #12 extends to whatever the track's part files are named, so finalisation still never removes a file it did not write. ## Tests Planted `<base>_track.gpx` files against `RecordingStore` and `MemoLibrary`, synthetic — **no real coordinates in fixtures.** This repository is public and a location fixture with real numbers in it is somebody's house. ## Done when - [ ] Deleting a memo with a track removes all three files. - [ ] A failed transcript deletion still leaves the audio and the row, unchanged from today. - [ ] A track file with no audio beside it does not appear as a memo. - [ ] The docs describe three files. --- *Milestone 2 of the Stash v3 rebuild. M2 is still app-side — **no sync, no account, no server**. It turns a list of memos into something you can open, listen to, read and see the route of. Sync arrives in M3. There is no `milestone/M2` label yet (creating org labels needs owner rights), so the title carries the milestone.* *Working agreement for every issue in this repo: feature branch, tested before the PR opens (on-device where the label says so), then Wes reviews the PR and we walk the code together. Docs update in the same commit. A PR that takes more than 20 minutes to review is too big — say so and split it.*
Author
Member

PR #46, and the decision record is Stash/stash-docs#7.

One thing in this issue's scope turned out to need a sharper answer than it was written with. The
.parts targeted-removal rule does extend to the track's part files, but not on both paths:
clearParts runs at transcript finalisation as well as at swipe-to-delete, so one list of
removable names would have the ordinary stop unlink a capture's route on its way out of assembly
once #34 writes them — and the launch sweep would do the same to a capture nobody spoke into. So
clearing now takes what the caller owns: publishing a transcript owns transcript parts and the
tail, deleting a memo owns everything the capture wrote.

Two consequences for #34 to know about: a parts folder can outlive a clean stop and means nothing
on its own (a transcript part left behind is the signal), and the launch sweep still looks for a
folder with no transcript beside it, so track recovery is #34's to answer.

Track parts are <base>_track.NNN.gpx in the existing folder, under the transcript's numbering.

Validated: 372 unit tests, lint clean, and a simulator check that a planted three-file memo is one
row while a lone _track.gpx is none. Not validated: swipe-to-delete against a three-file memo
through the UI — that path is covered by unit tests against a temporary directory, not by a tap.

PR #46, and the decision record is Stash/stash-docs#7. One thing in this issue's scope turned out to need a sharper answer than it was written with. The `.parts` targeted-removal rule does extend to the track's part files, but **not** on both paths: `clearParts` runs at transcript finalisation as well as at swipe-to-delete, so one list of removable names would have the ordinary stop unlink a capture's route on its way out of assembly once #34 writes them — and the launch sweep would do the same to a capture nobody spoke into. So clearing now takes what the caller owns: publishing a transcript owns transcript parts and the tail, deleting a memo owns everything the capture wrote. Two consequences for #34 to know about: a parts folder can outlive a clean stop and means nothing on its own (a transcript part left behind is the signal), and the launch sweep still looks for a folder with no transcript beside it, so track recovery is #34's to answer. Track parts are `<base>_track.NNN.gpx` in the existing folder, under the transcript's numbering. Validated: 372 unit tests, lint clean, and a simulator check that a planted three-file memo is one row while a lone `_track.gpx` is none. **Not validated:** swipe-to-delete against a three-file memo through the UI — that path is covered by unit tests against a temporary directory, not by a tap.
wk closed this issue 2026-08-09 18:22:03 -04:00
Sign in to join this conversation.
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#32
No description provided.