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

Merged
wk merged 1 commit from m2-05-track-file-triple into main 2026-08-09 18:22:02 -04:00
Member

Closes #32.

A memo is now up to three files: <base>_audio.m4a, <base>_transcription.vtt where somebody
spoke, and <base>_track.gpx where the route was recorded. Nothing writes a track yet — that
is #34. What lands here is everything that has to be ready before one exists, so there is never a
build where a track is on disk and swipe-to-delete strands it.

What changed

  • The names. trackFileName and trackPartFileName — the latter <base>_track.NNN.gpx in the
    <base>.parts/ folder the transcript's parts already use, under the same numbering. The two part
    parsers are thin wrappers over one strict rule rather than two copies of it, so what keeps
    .000, 0001 and a .sb-… temporary out cannot drift between them.
  • Deletion. Four targets: parts, transcript, track, audio last and only if nothing else failed.
    A track that will not go keeps the audio, which keeps the row and keeps the deletion retryable —
    the same rule the transcript has, and it matters more here because a track is a record of where
    somebody was.
  • Clearing the parts folder takes what the caller owns. clearParts is asked for .transcript
    or .wholeCapture, with no default. Publishing a transcript owns transcript parts and the
    unfinalised tail; deleting a memo owns everything the capture wrote.
  • Discovery is unchanged, and a test says so: a track with no audio beside it is not a memo.
  • Docs, in the same commit: README, AGENTS, the doc comments that carry the contract, and a
    decision record in stash-docs (Stash/stash-docs#7).

The design change made during the work

The first draft taught the parts clean-up about track parts globally. Codex caught that
clearParts runs on the ordinary stop path and not only on delete — so once #34 writes track
parts, the first normal stop after it lands would unlink the route on its way out of transcript
assembly, and the launch sweep would do the same to any capture nobody spoke into. Ownership became
the caller's to state.

Both mutations are covered: flipping either .transcript call site to .wholeCapture fails
assemblingATranscriptLeavesTheTrackPartsAndTheirFolderAlone and
aFolderOfNothingButTrackPartsSurvivesAssembly. Checked by hand, not assumed.

Codex

Plan review, code review, test review and security review are in .agent/m2-05-track-file-triple/,
with every finding's disposition in SUMMARY.md. The security pass found nothing at any level. The
test review found four gaps and all four were accepted — the no-speech branch could have lost every
route and stayed green, and the deletion fixture would have passed even if it deleted every .gpx
in the folder.

Validated

  • make test: 372 pass. make lint: 0 violations.
  • Simulator: planted a three-file memo and a lone _track.gpx in Documents. The memo is one row;
    the lone track is no row.
  • Installed on the device.

Not validated

  • Swipe-to-delete against a three-file memo through the UI. The deletion path is covered by unit
    tests against a temporary directory, not by a tap.
  • Anything about writing or reading a GPX file, because nothing does yet.
Closes #32. A memo is now up to three files: `<base>_audio.m4a`, `<base>_transcription.vtt` where somebody spoke, and `<base>_track.gpx` where the route was recorded. **Nothing writes a track yet** — that is #34. What lands here is everything that has to be ready before one exists, so there is never a build where a track is on disk and swipe-to-delete strands it. ## What changed - **The names.** `trackFileName` and `trackPartFileName` — the latter `<base>_track.NNN.gpx` in the `<base>.parts/` folder the transcript's parts already use, under the same numbering. The two part parsers are thin wrappers over one strict rule rather than two copies of it, so what keeps `.000`, `0001` and a `.sb-…` temporary out cannot drift between them. - **Deletion.** Four targets: parts, transcript, track, audio last and only if nothing else failed. A track that will not go keeps the audio, which keeps the row and keeps the deletion retryable — the same rule the transcript has, and it matters more here because a track is a record of where somebody was. - **Clearing the parts folder takes what the caller owns.** `clearParts` is asked for `.transcript` or `.wholeCapture`, with no default. Publishing a transcript owns transcript parts and the unfinalised tail; deleting a memo owns everything the capture wrote. - **Discovery is unchanged**, and a test says so: a track with no audio beside it is not a memo. - **Docs**, in the same commit: README, AGENTS, the doc comments that carry the contract, and a decision record in `stash-docs` (Stash/stash-docs#7). ## The design change made during the work The first draft taught the parts clean-up about track parts globally. Codex caught that `clearParts` runs on the ordinary stop path and not only on delete — so once #34 writes track parts, the first normal stop after it lands would unlink the route on its way out of transcript assembly, and the launch sweep would do the same to any capture nobody spoke into. Ownership became the caller's to state. Both mutations are covered: flipping either `.transcript` call site to `.wholeCapture` fails `assemblingATranscriptLeavesTheTrackPartsAndTheirFolderAlone` and `aFolderOfNothingButTrackPartsSurvivesAssembly`. Checked by hand, not assumed. ## Codex Plan review, code review, test review and security review are in `.agent/m2-05-track-file-triple/`, with every finding's disposition in `SUMMARY.md`. The security pass found nothing at any level. The test review found four gaps and all four were accepted — the no-speech branch could have lost every route and stayed green, and the deletion fixture would have passed even if it deleted every `.gpx` in the folder. ## Validated - `make test`: 372 pass. `make lint`: 0 violations. - Simulator: planted a three-file memo and a lone `_track.gpx` in Documents. The memo is one row; the lone track is no row. - Installed on the device. ## Not validated - **Swipe-to-delete against a three-file memo through the UI.** The deletion path is covered by unit tests against a temporary directory, not by a tap. - Anything about writing or reading a GPX file, because nothing does yet.
Teach discovery, deletion and the docs about <base>_track.gpx before M2-07
writes one. Nothing produces a track yet; what lands here is everything that
has to be ready before one exists, so there is never a build where a track is
on disk and swipe-to-delete strands it.

CaptureNaming gains the track's name and its parts' name — <base>_track.NNN.gpx
in the parts folder the transcript already uses, under the same numbering. The
two part parsers are wrappers over one strict rule rather than two copies of it.

Deletion takes the track between the transcript and the audio, keeping the rule
that the audio goes last and only if nothing else failed.

Clearing a parts folder now takes what the caller owns. Publishing a transcript
owns transcript parts and the tail; deleting a memo owns everything the capture
wrote. One list for both would have had the ordinary stop unlink a route on its
way out of transcript assembly once M2-07 lands.

Decision recorded in stash-docs.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
wk merged commit 50c3013f23 into main 2026-08-09 18:22:02 -04:00
wk deleted branch m2-05-track-file-triple 2026-08-09 18:22:03 -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!46
No description provided.