Voice memo files: Inspector 'Used in' backlinks to the entry, audio kind (not 'WebM video'), voice-memo icon everywhere #620

Open
opened 2026-10-01 10:13:06 +00:00 by kayg · 9 comments
Owner

Owner report (2026-10-01, Inspector + Calendar screenshots)

  1. "I created this voice memo from a journal entry but I don't see it linking back to the journal entry!" The Inspector of Documents/Voice Memos/2026-10-01 153915-7421 Voice memo 2026-10-01 15.38.webm shows "Linked notes" empty and nothing about the Log entry it was recorded on.
  2. "The icon for voice memos should be a voice memo icon and not a generic file icon?" Files, the Inspector and the Calendar attachment card show a generic play-document icon.
  3. The Inspector says "WebM video" for an audio-only voice memo.
    Fix:
  • Backlinks for files: the Inspector shows a "Used in" section: every Log entry, Event, Task and Note that references the file (the attachment index already knows; reuse the backlinks query, #… notes links). Each one is clickable and deep-linked. Linked notes stay as their own section.
  • Kind detection: sniff the container. WebM/Ogg/MP4 with no video track = audio. Files in Voice Memos (or recorder-made) show the kind "Voice memo", other audio "WebM audio" / "M4A audio". One shared kind helper for Files, Search, the Inspector and the Calendar.
  • Icons: voice memos get a voice-memo icon (a waveform/mic glyph in the shared icon set), and other audio an audio icon, consistently everywhere (Files list/grid, Inspector, Calendar chips #589, Search rows, Quick Look). Quick Look plays audio with a waveform player, not a video frame.
    Tests: a unit test for the kind sniffing (audio-only WebM → audio); an e2e: record on a Log entry → the Inspector of the file lists that entry under "Used in"; screenshots of the icons.
## Owner report (2026-10-01, Inspector + Calendar screenshots) 1. "I created this voice memo from a journal entry but I don't see it linking back to the journal entry!" The Inspector of `Documents/Voice Memos/2026-10-01 153915-7421 Voice memo 2026-10-01 15.38.webm` shows "Linked notes" empty and nothing about the Log entry it was recorded on. 2. "The icon for voice memos should be a voice memo icon and not a generic file icon?" Files, the Inspector and the Calendar attachment card show a generic play-document icon. 3. The Inspector says **"WebM video"** for an audio-only voice memo. **Fix:** - **Backlinks for files:** the Inspector shows a **"Used in"** section: every Log entry, Event, Task and Note that references the file (the attachment index already knows; reuse the backlinks query, #… notes links). Each one is clickable and deep-linked. Linked notes stay as their own section. - **Kind detection:** sniff the container. WebM/Ogg/MP4 with no video track = audio. Files in Voice Memos (or recorder-made) show the kind **"Voice memo"**, other audio "WebM audio" / "M4A audio". One shared kind helper for Files, Search, the Inspector and the Calendar. - **Icons:** voice memos get a voice-memo icon (a waveform/mic glyph in the shared icon set), and other audio an audio icon, consistently everywhere (Files list/grid, Inspector, Calendar chips #589, Search rows, Quick Look). Quick Look plays audio with a waveform player, not a video frame. **Tests:** a unit test for the kind sniffing (audio-only WebM → audio); an e2e: record on a Log entry → the Inspector of the file lists that entry under "Used in"; screenshots of the icons.
Author
Owner

Starting #620 on branch job/voicefiles-620, from base commit 9a6c38c3b7c8bbbdad9919cd2419f773d9c34b6e (working tree clean). I have read the repo contract and glossary. I am tracing the existing index backlinks, file kind, shared icons, and media preview paths before implementing the issue.

Starting #620 on branch `job/voicefiles-620`, from base commit `9a6c38c3b7c8bbbdad9919cd2419f773d9c34b6e` (working tree clean). I have read the repo contract and glossary. I am tracing the existing index backlinks, file kind, shared icons, and media preview paths before implementing the issue.
Author
Owner

Finding: crates/plugins/files/src/index.rs sets files_index.mime from mime_guess and the filename only; the recorder's .webm therefore indexes as video/webm, and Search/Calendar reuse that MIME. The recorder (apps/web/src/lib/composer/recorder.svelte.ts) already emits Voice memo … filenames, while DESIGN §40 says UI must not infer meaning from folders. I will classify recorder files from that existing filename marker and classify other media from the container tracks, then use one shared UI kind helper.

Finding: `crates/plugins/files/src/index.rs` sets `files_index.mime` from `mime_guess` and the filename only; the recorder's `.webm` therefore indexes as `video/webm`, and Search/Calendar reuse that MIME. The recorder (`apps/web/src/lib/composer/recorder.svelte.ts`) already emits `Voice memo …` filenames, while DESIGN §40 says UI must not infer meaning from folders. I will classify recorder files from that existing filename marker and classify other media from the container tracks, then use one shared UI kind helper.
Author
Owner

Committed the shared kind classifier and preview update: d31d31a8641379ca3d20739acd1b8ad3db6697f3.

Web checks:

svelte-check found 0 errors and 0 warnings

Web tests:

 Test Files  148 passed (148)
      Tests  1011 passed (1011)
   Start at  05:05:57
   Duration  61.38s (transform 51%, environment 18%, import 17%, tests 11%, setup 4%)

Environment  |component| jsdom was created 46 times · 54.62s total, 26% of tracked time
             create it once per worker with pool: 'vmThreads' (keeps per-file isolation) or isolate: false (shares it across files)
             learn more: https://vitest.dev/guide/improving-performance#test-environments
Committed the shared kind classifier and preview update: `d31d31a8641379ca3d20739acd1b8ad3db6697f3`. Web checks: ``` svelte-check found 0 errors and 0 warnings ``` Web tests: ``` Test Files 148 passed (148) Tests 1011 passed (1011) Start at 05:05:57 Duration 61.38s (transform 51%, environment 18%, import 17%, tests 11%, setup 4%) Environment |component| jsdom was created 46 times · 54.62s total, 26% of tracked time create it once per worker with pool: 'vmThreads' (keeps per-file isolation) or isolate: false (shares it across files) learn more: https://vitest.dev/guide/improving-performance#test-environments ```
Author
Owner

Committed the Inspector usage endpoint and server coverage for Log, Event, Task, Note, cross-User scope, and path traversal: f3b3f4b0ed1fb17603a8e711fc9fc3ce9b16fd5b.

cargo clippy -p calternal-plugin-notes --all-targets -- -D warnings:

    Checking calternal-plugin-notes v0.0.1 (/home/kayg/Developer/calternal-wt/voicefiles-620/crates/plugins/notes)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 9.94s

cargo test -p calternal-plugin-notes:

test result: ok. 164 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 145.92s

test completing_reminder_without_description_preserves_notes ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.55s

   Doc-tests calternal_plugin_notes

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Committed the Inspector usage endpoint and server coverage for Log, Event, Task, Note, cross-User scope, and path traversal: `f3b3f4b0ed1fb17603a8e711fc9fc3ce9b16fd5b`. `cargo clippy -p calternal-plugin-notes --all-targets -- -D warnings`: ``` Checking calternal-plugin-notes v0.0.1 (/home/kayg/Developer/calternal-wt/voicefiles-620/crates/plugins/notes) Finished `dev` profile [unoptimized + debuginfo] target(s) in 9.94s ``` `cargo test -p calternal-plugin-notes`: ``` test result: ok. 164 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 145.92s test completing_reminder_without_description_preserves_notes ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.55s Doc-tests calternal_plugin_notes running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ```
Author
Owner

Post-merge finding: cargo test -p calternal-plugin-notes exposed a test isolation race. Every parallel test used the same User ID, but Notes writer locks are shared across routers, so a nonblocking Journal read could see another test's lock and return 404. I kept the assertions and assigned each test Home a unique User ID. Evidence after the fix: cargo clippy -p calternal-plugin-notes --all-targets -- -D warnings passed; cargo test -p calternal-plugin-notes passed (169 unit tests and 1 integration test).

Post-merge finding: cargo test -p calternal-plugin-notes exposed a test isolation race. Every parallel test used the same User ID, but Notes writer locks are shared across routers, so a nonblocking Journal read could see another test's lock and return 404. I kept the assertions and assigned each test Home a unique User ID. Evidence after the fix: cargo clippy -p calternal-plugin-notes --all-targets -- -D warnings passed; cargo test -p calternal-plugin-notes passed (169 unit tests and 1 integration test).
Author
Owner

Production e2e finding: recorder files are named with a timestamp before the words 'Voice memo' (for example, ). The old anchored matcher treated them as generic audio. I updated the shared classifier to recognize the recorder marker anywhere in the filename and audio inside , then passed the focused 12-test glyph checks plus the full web suite (153 files, 1,054 tests).

Production e2e finding: recorder files are named with a timestamp before the words 'Voice memo' (for example, ). The old anchored matcher treated them as generic audio. I updated the shared classifier to recognize the recorder marker anywhere in the filename and audio inside , then passed the focused 12-test glyph checks plus the full web suite (153 files, 1,054 tests).
Author
Owner

Production e2e finding: recorder files use a timestamp prefix before Voice memo (example: 2026-10-02 073127-2b5c Voice memo 2026-10-02 07.31.webm). The old anchored matcher treated them as generic audio. I updated the shared classifier to recognize the recorder marker anywhere in the filename and audio inside Voice Memos, then passed the focused 12-test glyph checks and the full web suite (153 files, 1,054 tests).

Production e2e finding: recorder files use a timestamp prefix before Voice memo (example: 2026-10-02 073127-2b5c Voice memo 2026-10-02 07.31.webm). The old anchored matcher treated them as generic audio. I updated the shared classifier to recognize the recorder marker anywhere in the filename and audio inside Voice Memos, then passed the focused 12-test glyph checks and the full web suite (153 files, 1,054 tests).
Author
Owner

Head: b7ef7a2ab57f45b5d46cd19b4560215acae918e3

The Inspector now has a separate Used in section with deep links to Log entries, Events, Tasks, and Notes. Linked notes remain a separate section. Container sniffing distinguishes audio-only WebM/Ogg/MP4 from video. Voice memos and other audio use shared waveform and audio glyphs in Files, Search, Calendar, the Inspector, and Quick Look. Quick Look plays audio with the waveform player.

Checks

  • cargo fmt --all --check — passed (exit 0; no output).
  • cargo clippy -p <crate> --all-targets -- -D warnings — passed for calternal-media, calternal-api, calternal-plugin-notes, calternal-search, calternal-plugin-files, calternal-plugin-photos, and calternal-server.
  • cargo test — calternal-media: 4 passed; calternal-api: 9 passed; calternal-plugin-notes: 169 unit + 1 integration passed; calternal-search: 36 unit passed, 1 ignored, all integrations passed (ask-evaluation 1, citations 1, indexer 21, operators 5, query_properties 2, relevance 1 passed + 2 ignored, retrieval 4); calternal-plugin-files: 146 passed, 1 ignored; calternal-plugin-photos: 46 passed, 2 ignored; calternal-server: 107 passed, 3 ignored.
  • bun run check: svelte-check found 0 errors and 0 warnings
  • bun run test: Test Files 153 passed (153); Tests 1054 passed (1054); Duration 124.57s
  • Production e2e output:
    • Voice files 620: Quick Look audio, Voice memo glyph and Log backlink passed at every width and theme
    • Voice files 620: Files list/grid and Inspector passed at every width and theme
    • Voice files 620: Search glyph passed at every width and theme
    • Voice files 620: Calendar attachment icon passed at every width and theme
  • Adversarial output: Notes Used in #620 adversarial probe passed: traversal, malformed and oversized queries, Unicode path, 48 concurrent reads

Benchmark finding

The local Used in profile warmed with 128 backlinks. Its average phase stopped with AssertionError: average did not return all real Log backlinks; the HTTP 200 check passed, but not every measured response had 128 rows. The run emitted no latency, CPU, RSS, or burst metrics. docs/perf/baseline.json has no notes.used-in baseline. I did not repeat the measurement under shared-host load.

The existing calendar-preview-421.mjs run also timed out before its #620 section while waiting for the Composer to detach after the Journal edit. The standalone #620 production e2e above passed.

Decisions where DESIGN is silent

  • The Used in response uses string kinds (log, event, task, note), stable source IDs, and an optional date for Log entries. The response is bounded at 1,000 rows and returns 413 above that limit.
  • Media sniffing reads a bounded 1 MiB prefix; MP4 moov boxes are limited to 16 MiB. Malformed or unsupported containers keep the existing MIME guess. A container with both audio and video is video.
  • A file is a Voice memo when it is audio and either its name contains the recorder marker or its parent folder is Voice Memos (case-insensitive).
  • A Note that references a file can appear in both Used in and Linked notes; the sections keep their distinct purposes.

Files

The change touches 37 files: the shared media crate; Files, Notes, Search, and API crates; generated OpenAPI/client types; shared UI glyph, Calendar, and Quick Look components; the Inspector and Search rows; e2e and adversarial probes; the local benchmark; and Cargo.lock. The production e2e is apps/web/e2e/voicefiles-620.mjs.

Screenshot evidence

All 30 real production-build screenshots are attached here.

Surface 390 light 390 dark 820 light 820 dark 1440 light 1440 dark
Quick Look + Used in PNG PNG PNG PNG PNG PNG
Files list + Inspector PNG PNG PNG PNG PNG PNG
Files grid + Inspector PNG PNG PNG PNG PNG PNG
Search PNG PNG PNG PNG PNG PNG
Calendar attachment PNG PNG PNG PNG PNG PNG
## Completed: voice memo backlinks, media kinds, and icons **Head:** `b7ef7a2ab57f45b5d46cd19b4560215acae918e3` The Inspector now has a separate **Used in** section with deep links to Log entries, Events, Tasks, and Notes. Linked notes remain a separate section. Container sniffing distinguishes audio-only WebM/Ogg/MP4 from video. Voice memos and other audio use shared waveform and audio glyphs in Files, Search, Calendar, the Inspector, and Quick Look. Quick Look plays audio with the waveform player. ### Checks - `cargo fmt --all --check` — passed (exit 0; no output). - `cargo clippy -p <crate> --all-targets -- -D warnings` — passed for `calternal-media`, `calternal-api`, `calternal-plugin-notes`, `calternal-search`, `calternal-plugin-files`, `calternal-plugin-photos`, and `calternal-server`. - `cargo test` — `calternal-media`: 4 passed; `calternal-api`: 9 passed; `calternal-plugin-notes`: 169 unit + 1 integration passed; `calternal-search`: 36 unit passed, 1 ignored, all integrations passed (ask-evaluation 1, citations 1, indexer 21, operators 5, query_properties 2, relevance 1 passed + 2 ignored, retrieval 4); `calternal-plugin-files`: 146 passed, 1 ignored; `calternal-plugin-photos`: 46 passed, 2 ignored; `calternal-server`: 107 passed, 3 ignored. - `bun run check`: `svelte-check found 0 errors and 0 warnings` - `bun run test`: `Test Files 153 passed (153); Tests 1054 passed (1054); Duration 124.57s` - Production e2e output: - `Voice files 620: Quick Look audio, Voice memo glyph and Log backlink passed at every width and theme` - `Voice files 620: Files list/grid and Inspector passed at every width and theme` - `Voice files 620: Search glyph passed at every width and theme` - `Voice files 620: Calendar attachment icon passed at every width and theme` - Adversarial output: `Notes Used in #620 adversarial probe passed: traversal, malformed and oversized queries, Unicode path, 48 concurrent reads` ### Benchmark finding The local Used in profile warmed with 128 backlinks. Its average phase stopped with `AssertionError: average did not return all real Log backlinks`; the HTTP 200 check passed, but not every measured response had 128 rows. The run emitted no latency, CPU, RSS, or burst metrics. `docs/perf/baseline.json` has no `notes.used-in` baseline. I did not repeat the measurement under shared-host load. The existing `calendar-preview-421.mjs` run also timed out before its #620 section while waiting for the Composer to detach after the Journal edit. The standalone #620 production e2e above passed. ### Decisions where DESIGN is silent - The Used in response uses string kinds (`log`, `event`, `task`, `note`), stable source IDs, and an optional date for Log entries. The response is bounded at 1,000 rows and returns 413 above that limit. - Media sniffing reads a bounded 1 MiB prefix; MP4 `moov` boxes are limited to 16 MiB. Malformed or unsupported containers keep the existing MIME guess. A container with both audio and video is video. - A file is a Voice memo when it is audio and either its name contains the recorder marker or its parent folder is `Voice Memos` (case-insensitive). - A Note that references a file can appear in both Used in and Linked notes; the sections keep their distinct purposes. ### Files The change touches 37 files: the shared media crate; Files, Notes, Search, and API crates; generated OpenAPI/client types; shared UI glyph, Calendar, and Quick Look components; the Inspector and Search rows; e2e and adversarial probes; the local benchmark; and `Cargo.lock`. The production e2e is `apps/web/e2e/voicefiles-620.mjs`. ### Screenshot evidence All 30 real production-build screenshots are attached here. | Surface | 390 light | 390 dark | 820 light | 820 dark | 1440 light | 1440 dark | |---|---|---|---|---|---|---| | Quick Look + Used in | [PNG](https://git.kayg.org/attachments/221ff458-9fcf-4628-9401-1cf31eef6eeb) | [PNG](https://git.kayg.org/attachments/4650a534-e7f4-4692-9fea-f20f4ce3b801) | [PNG](https://git.kayg.org/attachments/bc22a5ad-4892-4508-927e-627fcb5757ab) | [PNG](https://git.kayg.org/attachments/4312ffd0-afdd-4051-a35b-500aaa720ef3) | [PNG](https://git.kayg.org/attachments/95a3eca9-dc99-4239-98f0-23730648c282) | [PNG](https://git.kayg.org/attachments/baaf00ad-3a82-4bf9-9b54-e46ac8786891) | | Files list + Inspector | [PNG](https://git.kayg.org/attachments/68150013-0c18-4ef5-9ccc-a5fb22a6c31e) | [PNG](https://git.kayg.org/attachments/e4783a1e-8c09-4812-945b-8c5f41ef5c7f) | [PNG](https://git.kayg.org/attachments/7e3fb64e-6ebf-495e-9f26-a8dcce73e21e) | [PNG](https://git.kayg.org/attachments/f555bd51-1d28-478e-b685-02b6df0d80dc) | [PNG](https://git.kayg.org/attachments/7e633678-aed3-4665-92b7-7bfe83af584f) | [PNG](https://git.kayg.org/attachments/3c497837-1ce6-4db5-9495-d04ba1682843) | | Files grid + Inspector | [PNG](https://git.kayg.org/attachments/5db7cac0-31c5-46da-b143-75db7da7cde7) | [PNG](https://git.kayg.org/attachments/516d6d74-abfe-4c33-8863-37cb07b734fc) | [PNG](https://git.kayg.org/attachments/25db18d0-bd9b-4d89-bd28-ece039e71e3c) | [PNG](https://git.kayg.org/attachments/571db171-9fb7-4400-a0fe-2ea213517cbc) | [PNG](https://git.kayg.org/attachments/9159c001-0c57-43bc-b8b6-42a19ab98cee) | [PNG](https://git.kayg.org/attachments/9711f959-6bb5-4642-bc5d-933f27c6c959) | | Search | [PNG](https://git.kayg.org/attachments/ace42c98-7e30-4095-813b-60f393289f14) | [PNG](https://git.kayg.org/attachments/48da0a7a-6cc4-417d-8755-006d968bb37d) | [PNG](https://git.kayg.org/attachments/8ab82939-24ba-4173-ab48-eaf4d0a9ae27) | [PNG](https://git.kayg.org/attachments/7c3d91fb-705e-49b3-a2b7-66d106e49c46) | [PNG](https://git.kayg.org/attachments/934f9967-3123-4528-88f0-23730648c282) | [PNG](https://git.kayg.org/attachments/5bf9497f-7dac-4111-8cb6-005f8649f4a5) | | Calendar attachment | [PNG](https://git.kayg.org/attachments/cf59c062-28cb-4a92-88c7-0ddb336815b5) | [PNG](https://git.kayg.org/attachments/5df34932-0607-4e84-937d-4fa8b1053cd8) | [PNG](https://git.kayg.org/attachments/64dc09a1-aea6-4f2b-8d0c-939580354aeb) | [PNG](https://git.kayg.org/attachments/2c335d6f-b2cf-4233-b828-115049eeab56) | [PNG](https://git.kayg.org/attachments/b0ba439f-1256-4ccc-af80-50248c2d252a) | [PNG](https://git.kayg.org/attachments/3ed2cf29-3585-4f50-a13d-b7bca4670a77) |
Author
Owner

Merge-audit evidence:

  • origin/job/voicefiles-620 changes packages/ui/src/components/viewer/QuickLook.svelte to render audio and voice-memo with a native <audio controls> element (current branch line 242).
  • origin/job/calcard-series changes the same Quick Look audio branch to use VoicePlayback (current branch line 256). Issue #622 owns this waveform player.

Keep VoicePlayback as the one Quick Look audio player. Apply the voice-memo kind check and matching glyph from #620 to that branch. Do not keep a second native player. The shared FileIcon.svelte also needs one combined change with textthumb-652: #620 adds the voice-memo kind; #652 adds the accent prop.

Merge-audit evidence: - `origin/job/voicefiles-620` changes `packages/ui/src/components/viewer/QuickLook.svelte` to render `audio` and `voice-memo` with a native `<audio controls>` element (current branch line 242). - `origin/job/calcard-series` changes the same Quick Look audio branch to use `VoicePlayback` (current branch line 256). Issue #622 owns this waveform player. Keep `VoicePlayback` as the one Quick Look audio player. Apply the `voice-memo` kind check and matching glyph from #620 to that branch. Do not keep a second native player. The shared `FileIcon.svelte` also needs one combined change with textthumb-652: #620 adds the `voice-memo` kind; #652 adds the `accent` prop.
Sign in to join this conversation.
No labels
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
kayg/calternal#620
No description provided.