perf: move transcript restyle + saved-transcript analytics off the main actor#1072
Open
r3dbars wants to merge 1 commit into
Open
perf: move transcript restyle + saved-transcript analytics off the main actor#1072r3dbars wants to merge 1 commit into
r3dbars wants to merge 1 commit into
Conversation
…in actor Every transcript save ran MeetingTranscriptStyler.restyleTranscript synchronously on the main actor (full read, rewrite, and file/audio-dir rename), and the saved-transcript analytics re-read the whole file again on the main actor just to bucket properties. Multi-hour meetings produce multi-MB markdown, so the UI hitched exactly at "transcript saved". - Restyle now runs on a serialized detached task; only the published state updates, live-sidecar attach, and diagnostics hop back to the main actor. Restyles are chained so two passes never touch the same artifacts concurrently, and a stale-result guard drops superseded updates while retained-audio compression still runs for every save. - savedTranscriptAnalyticsProperties is now nonisolated static, runs detached, awaits the in-flight restyle so it reads the renamed artifact (it previously read the pre-rename path, which the synchronous restyle had often already renamed away), and uses the bounded frontmatter chunk reader instead of loading the whole file. - The restyle persist path fails closed when the body carries transcript text the entry parser cannot understand, instead of destructively replacing it with "_No transcript captured._". Genuinely empty transcripts still get the placeholder rewrite. Gates: build-deps.sh --force, build.sh --no-open, run-tests.sh (4660/4660), run-integration-smoke.sh. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Every transcript save ran
MeetingTranscriptStyler.restyleTranscriptsynchronously on the main actor — a full transcript read, rewrite, and file + audio-dir rename — andsavedTranscriptAnalyticsPropertiesre-read the entire transcript again on the main actor just to bucket analytics. Multi-hour meetings produce multi-MB markdown, so the UI hitched exactly at "transcript saved". (Audit-verified finding.)Product Impact
meetingsmeeting reliabilityWhat changed
MeetingSessionController: thetaskManager.$lastSavedTranscriptURLsubscription now runs the restyle on a serialized detached task (restyleSavedTranscriptInBackground); only the published state updates, live-sidecar attach, and diagnostics hop back to the main actor. Restyles are chained so two passes never touch the same artifacts concurrently (matters for the speaker-review re-save), and a stale-result guard drops superseded updates while retained-audio compression still runs for every save.savedTranscriptAnalyticsPropertiesis nownonisolated staticand runs detached. It awaits the in-flight restyle so it reads the renamed artifact — previously it read the pre-rename path, which the synchronous restyle had often already renamed away, silently producing empty analytics buckets — and it uses the boundedTranscriptFrontmatter.readValues(from:)chunk reader instead of loading the whole file. TheAnalyticsReporter.trackcall itself stays on the main actor (the reporter's lazydistinctIDis not thread-safe).MeetingTranscriptStyler: persisting now fails closed when the body carries transcript text the entry parser cannot understand — no rewrite, no rename, logged asmeeting_transcript_restyle_skipped— instead of destructively replacing the body with_No transcript captured._. Genuinely empty transcripts (empty block, or only---/*Generated by...remnants, matching the real saver's empty shape) still get the placeholder rewrite.RepoCommandContractTestsfollows the renamed analytics function.Sources/Meeting/CLAUDE.mdflow step 12 updated.How I checked it
.agents/test-matrix.ymlfor the files changed (Sources/Meeting/**rule)bash build-deps.sh --forcebash build.sh --no-openbash run-tests.sh— 4660/4660 passed, includingMeetingTranscriptStylerTestsand the repo-contract suitebash run-integration-smoke.shRisk Review
meeting_transcript_savedevent and allowlisted bucketed properties; only timing/threading changedNotes
Known trade-off: if a second save lands while the first save's restyle is still in flight, the first meeting's live-Codex final-transcript attach can be skipped — but the attach guard (
lastSavedTranscriptTaskId == awaitedJobID) would have rejected it at that point anyway, and the activeCount-driven attach path provides a second chance before that window closes.Side effect worth knowing: because the restyle no longer runs inside the
@PublishedwillSet,populateSavedMetadatainTranscriptionTaskManagernow reads the transcript before any rename, solastSavedTitle/lastSavedDuration/lastSavedSpeakerCountpopulate correctly in cases where they previously read a just-renamed-away path.🤖 Generated with Claude Code