feat(calls): transcripts archive page + harden 1:1 toggle (LC-394) #408

Merged
longjacksonle merged 1 commit from feat/lc-394-transcript-archive into main 2026-06-20 08:22:08 +02:00

Fixes LC-394 (follow-up to the LC-393 transcription epic). From testing: transcripts were hard to find ("I don't know where it saves"), and 1:1 call transcription seemed unreliable.

1. Transcripts archive (the main ask)

Transcripts were only reachable via the one-off "transcript saved" system message in the room - no list, no home. Added a GET /transcripts archive listing every transcript the viewer can access (their DM calls + voice channels they belong to), newest first. Each row headlines the DM peer's name (or the voice-room name), with the start time, status (in progress / ended), segment count, and a link to the full transcript. A sidebar nav entry (next to Saved / Scheduled) makes it discoverable.

Access: each candidate is gated with the same is_room_accessible check the single-transcript page uses (bounded scan of the most recent, then per-row access filter), so a transcript from a room you can't see never appears. The new test archive_lists_only_accessible_transcripts proves a member sees their transcript and a non-member does not.

So: enclave/voice transcripts now have a visible home, and you can browse past calls.

2. 1:1 transcription robustness

Voice-channel transcription worked, but a 1:1 call showed no live transcription. The server + client paths are symmetric with the working voice path; the one 1:1-specific dependency was that the in-call toggle resolved its room only from the window.__lcCallRoom global. call.js now also stamps data-lc-room on the toggle when a call goes active (cleared on end), so transcribe.js resolves the room the same bulletproof way the voice toggle does. This removes the timing/global dependency as a failure mode.

Honest note: I couldn't reproduce the 1:1 failure in code (gate, broadcast, capture, and caption display all looked symmetric with voice, and DMs do populate room_members), so this is a defensive hardening of the most likely cause rather than a confirmed single root cause. If 1:1 still shows nothing after this, the next thing to check is whether the deployed build is current and the browser console for a failed /call/{id}/transcript/start.

Testing

  • tests/transcripts.rs -> 8 green (added the archive access test); just check, just test, just test-saas all exit 0; just build-css regenerated.
  • The 1:1 toggle change + archive rendering are also exercised manually (browser).

No operator action: no new env var, no migration. This is effectively the start of LC-393's Phase 4 (browse).

Fixes LC-394 (follow-up to the LC-393 transcription epic). From testing: transcripts were hard to find ("I don't know where it saves"), and 1:1 call transcription seemed unreliable. ## 1. Transcripts archive (the main ask) Transcripts were only reachable via the one-off "transcript saved" system message in the room - no list, no home. Added a **`GET /transcripts` archive** listing every transcript the viewer can access (their DM calls + voice channels they belong to), newest first. Each row headlines the **DM peer's name** (or the **voice-room name**), with the start time, status (in progress / ended), segment count, and a link to the full transcript. A **sidebar nav entry** (next to Saved / Scheduled) makes it discoverable. Access: each candidate is gated with the same `is_room_accessible` check the single-transcript page uses (bounded scan of the most recent, then per-row access filter), so a transcript from a room you can't see never appears. The new test `archive_lists_only_accessible_transcripts` proves a member sees their transcript and a non-member does not. So: enclave/voice transcripts now have a visible home, and you can browse past calls. ## 2. 1:1 transcription robustness Voice-channel transcription worked, but a 1:1 call showed no live transcription. The server + client paths are symmetric with the working voice path; the one 1:1-specific dependency was that the in-call toggle resolved its room only from the `window.__lcCallRoom` global. `call.js` now also **stamps `data-lc-room` on the toggle when a call goes active** (cleared on end), so `transcribe.js` resolves the room the same bulletproof way the voice toggle does. This removes the timing/global dependency as a failure mode. Honest note: I couldn't reproduce the 1:1 failure in code (gate, broadcast, capture, and caption display all looked symmetric with voice, and DMs do populate `room_members`), so this is a defensive hardening of the most likely cause rather than a confirmed single root cause. If 1:1 still shows nothing after this, the next thing to check is whether the deployed build is current and the browser console for a failed `/call/{id}/transcript/start`. ## Testing - `tests/transcripts.rs` -> 8 green (added the archive access test); `just check`, `just test`, `just test-saas` all exit 0; `just build-css` regenerated. - The 1:1 toggle change + archive rendering are also exercised manually (browser). No operator action: no new env var, no migration. This is effectively the start of LC-393's Phase 4 (browse).
feat(calls): transcripts archive page + harden 1:1 toggle (LC-394)
All checks were successful
check-secrets / Kingfisher (push) Successful in 4s
check-secrets / TruffleHog (push) Successful in 6s
check-secrets / Nosey parker (push) Successful in 6s
check-secrets / TruffleHog (pull_request) Successful in 4s
check-secrets / Nosey parker (pull_request) Successful in 6s
check-secrets / Kingfisher (pull_request) Successful in 6s
Create release / Create release from merged PR (pull_request) Has been skipped
Check / clippy + fmt + tests (pull_request) Successful in 6m19s
ebbc73b4a6
Follow-up to LC-393. Two things from testing:

1. Transcripts were only reachable via the one-off "transcript saved" message, so users had no way to find past ones. Add a transcripts archive at GET /transcripts listing every transcript the viewer can access (their DM calls + voice channels they belong to), newest first - each row headlining the DM peer / voice-room name, with the start time, status, segment count, and a link to the full transcript. Each candidate is gated with the same is_room_accessible check the single-transcript page uses, so nothing leaks. A sidebar nav entry (alongside Saved / Scheduled) makes it discoverable.

2. 1:1 call transcription robustness: the in-call toggle resolved its room only from the window.__lcCallRoom global. call.js now also stamps data-lc-room on the toggle when a call goes active (cleared on end), so transcribe.js resolves the room the same bulletproof way the voice toggle does.

New db::transcripts::list_recent (transcript + room + segment count), routes::transcripts::index, the TranscriptIndexPage view + transcripts/index.html, en/es strings, and an archive access-filtering test.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
longjacksonle deleted branch feat/lc-394-transcript-archive 2026-06-20 08:22:08 +02:00
Sign in to join this conversation.
No reviewers
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
psa-systems/lets-chat!408
No description provided.