Skip to content

Fix runaway memory in idle and audio paths - #1667

Merged
r3dbars merged 6 commits into
mainfrom
codex/fix-memory-runaway-20260808
Aug 8, 2026
Merged

Fix runaway memory in idle and audio paths#1667
r3dbars merged 6 commits into
mainfrom
codex/fix-memory-runaway-20260808

Conversation

@r3dbars

@r3dbars r3dbars commented Aug 8, 2026

Copy link
Copy Markdown
Owner

Summary

  • keep a truly idle app lightweight: remove the recurring ScreenCaptureKit permission probe and make heavyweight model warmup opt-in
  • hard-bound every risky audio retention boundary: PCM file-write queues, shared meeting-mic relay, timed-out CoreAudio workers, and retired AVAudioEngine graphs
  • make stop nonblocking while each bounded file queue drains its admitted tail before closing exact-generation writer ownership
  • delete the always-on live meeting transcript preview and its duplicate audio/UI pipeline; final meeting recording and transcription are unchanged

What was happening

The report shows Transcripted at roughly 135.56 GB while not recording. The screenshot proves the runaway belongs to the Transcripted process, but it cannot identify the exact allocator after the fact.

The audit found multiple paths that could grow without a hard ceiling:

  • serial WAV writer queues retained every incoming PCM buffer if storage stalled
  • live preview added another always-on stream of PCM/transcript work
  • repeated CoreAudio timeouts could retire a fresh blocked worker every time
  • route-notification bursts created task-per-event lookups and native graph churn
  • onboarding re-probed ScreenCaptureKit every second, while model warmup was eager by default

"Not recording" is compatible with either a true clean-idle trigger or work left behind after an earlier capture. This change closes both classes instead of betting on one screenshot interpretation.

Deterministic proof

  • blocked PCM relay, old code: median RSS growth about 135.6 MB per 128-buffer burst
  • blocked PCM relay, fixed code: 2.949–2.982 MB growth across three runs
  • permanently blocked CoreAudio route work, old code: 12/12 workers entered
  • fixed circuit: 2 workers entered, then 10 immediate circuit-open failures, across three runs
  • exact signed app, no recording, isolated 15-minute soak:
    • physical footprint: 26.000 MiB -> 26.000 MiB
    • RSS: 87,136 KiB -> 77,072 KiB
    • threads: 16 -> 12–13
    • no repeating permission probe, model load, error, or background CPU churn

Verification

  • bash build-deps.sh --force
  • bash build.sh --no-open
  • bash run-tests.sh — 12,106 passed, 0 failed
  • swift test — 1,013 executed, 13 skipped, 0 failures
  • bash run-integration-smoke.sh
  • bash scripts/ops/transcripted-qa-bench.sh --mode full — exact-head run qa-20260808-155948: PASS, 15 checks, 0 blocking failures, 1 non-blocking local-state warning
  • deterministic memory/backpressure harnesses repeated three times

Independent review

Successive independent reviews against the real PR base found and drove nine accepted corrections:

  • a capped zombie-engine path now fails closed instead of reusing a known-zombie graph
  • retirement-cap failure now marks dictation interrupted so a listening UI cannot outlive stopped capture
  • stop now closes writers from serial queue barriers so already-admitted tail audio cannot be dropped
  • capture-callback admission is lock-free; meeting host fan-out moved behind the bounded serial handoff
  • a process-wide timed-work circuit keeps every blocked CoreAudio worker counted until it really returns
  • old mic tails keep their own generation, format, channel count, and write-error counter across a fast successor start
  • borrowed dictation now has a separate bounded handoff and both handoff tails are drained before finalization
  • the inert recording-strip drag surface is no longer exposed to VoiceOver as a button
  • the lossy secondary mic relay queue was deleted; Core's bounded FIFO is now the only ordered handoff

The ownership repair also rejects a late session writer that arrives after its generation was stopped. The final independent follow-up review is clean, exact-head full QA passed, and hosted CI is green.

Proof boundary

The affected machine's original process was not captured with a memgraph, so the exact historical allocator remains unknown. The automated gate proves bounded behavior and a flat clean-idle process on this build. Real Zoom/WebRTC and Bluetooth hardware checks remain separate manual proof.

@r3dbars
r3dbars merged commit ecd15e0 into main Aug 8, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant