fix(director): air talk instead of blocking on an unready music pick [spec 04] - #31
Merged
Merged
Conversation
…[spec 04] The music branch awaited an in-flight-but-not-done prefetched pick, blocking the loop ~56s on a slow long-playlist resolve even with a warm talk beat already buffered (observed live: `music.pick prefetched=True elapsed_s=56.52`). Guard _play_music_segment: when the prefetched pick is still resolving, return to talk and re-attempt music at the next boundary. The pick keeps resolving in the background (slot not cleared, so no duplicate prefetch) and the depth-2 talk look-ahead covers the search adaptively — however long it takes — with no dead air and no hardcoded talk-for-N duration. The cold (nothing-prefetched) and resolved-pick paths are unchanged. Regression test: a fake TrackSource whose pick never resolves yields continuous talk and completes under max_segments (pre-fix the run hung). Aligns spec04 §3.1 Consume + acceptance criterion #4. Co-Authored-By: Claude Opus 4.8 (1M context) <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.
Problem
A real listening run (
.dev/dev.log) opened with ~63s of dead air before thefirst song. A talk beat was already synthesized and buffered, but when music was
due the branch entered
_play_music_segment→_take_pickand blocked ~56sawaiting a not-yet-resolved prefetched pick instead of airing the warm buffered
talk. The dev-log seam shows it plainly:
prefetched=Truewith a 56s elapsed means the prefetch was in flight but notdone, and the music branch awaited it — blocking the whole loop.
Root cause: the music branch awaited an in-flight prefetch, blocking the loop
even when talk was ready.
Fix
Guard
Director._play_music_segment: when the prefetched pick is stillresolving (in flight, not
.done()), return to talk and re-attempt music atthe next boundary. The pick keeps resolving in the background — the slot is not
cleared, so no duplicate prefetch fires — and the depth-2 talk look-ahead
(spec 04 §3.3) covers the search adaptively, however long it takes, with no
dead air and no hardcoded "talk for N minutes" duration.
The cold path (nothing prefetched — the first-ever segment) and the resolved-pick
path are byte-for-byte unchanged; only an in-flight pick now defers instead
of blocking.
Tests
test_music_does_not_block_on_an_unresolved_pick_airs_talk: afake
TrackSourcewhose pick never resolves now yields continuous talk andthe run completes under
max_segments. Pre-fix the music branch awaited thepick and the run hung (the test times out on old code).
(they exercise the untouched cold path).
Spec
Aligned
specs/spec04/04-no-dead-air.md§3.1 Consume bullet (no longer "finishwhat's left" — a resolving pick now defers to talk) and added acceptance
criterion #4 (no-block / dead-air).
Implements specs/spec04/04-no-dead-air.md
Peer review
Peer review (codex gpt-5.5): 1 finding, 0 applied, 1 dismissed. The finding — a
resolved pick held across several talk boundaries under erratic
RandomCadence/BrainCadencegrows stale and blocks a fresher prefetch — is aspec-accepted trade-off (§3.1 "Staleness (accepted)" + §6 open question on
mood-staleness tolerance) and the intended single-slot "one pick ahead" design
(re-prefetching every talk would waste the expensive yt-dlp resolves slice 1
exists to avoid). Not a regression: the change adds at most one deferral boundary
to an already-accepted staleness window, and music airs whenever cadence next
chooses it.
AI coding brief
Original request: handoff
scratch/handoff-spec04-followups.mdTask 1 — areal listening run (
.dev/dev.log) showed ~63s dead air before the first songbecause the music branch blocked ~56s awaiting a not-yet-ready prefetched pick
instead of airing the already-buffered warm talk. Why: cold-start
responsiveness / no-dead-air (spec 04).
Manual interventions: none — the fix followed the handoff's diagnosis
directly.
Retro: the handoff pre-diagnosed the root cause with the exact dev.log line,
which made this a one-guard fix. Precise seam-level evidence (the
prefetched=True elapsed_s=56.52line) is what turned a vague "dead air" symptominto a targeted change — capture the deterministic seam in the bug report and the
fix writes itself.
🤖 Generated with Claude Code