Whisper transcribed the intern as "Devin" in 21 of 58 transcripts — he is Devon
everywhere else: backend/services/intern.py, the website, and the show's lore.
Five files used both spellings for the same character, so this was transcription
drift rather than two people. Context confirms every instance is the intern
("our new intern, Devin here", "Devin, where's my coffee?").
436 replacements across 22 files, 384 insertions against 384 deletions — pure
substitution, no content added or lost. Speaker labels went from 219 DEVIN: /
17 DEVON: to 236 DEVON:.
This mattered now because the transcripts stop being .txt files nobody reads and
become indexed text on 57 episode pages.
Root cause is unfixed: the Whisper initial prompt in transcription.py does not
seed "Devon" as a proper noun, so new episodes will drift again. Added a test
that fails if any transcript reintroduces the misspelling.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
add_episode_to_sitemap() was removed in the previous commit, so nothing was
writing the sitemap any more. Publishing now shells out to
generate_episode_pages.py --sitemap right after the transcript is copied into
website/transcripts/, which builds the new episode's static page and rebuilds
the sitemap from the feed.
Deliberately non-fatal: by this point the audio is live on Castopod and the RSS
feed has been rebuilt, so a generator failure must not abort the publish. It
warns and moves on, and the page lands on the next run. Covered for non-zero
exit, timeout, and a missing generator script.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The renderer emits .transcript-turn and .transcript-speaker, neither of which
had any CSS, so speaker labels and turns rendered unstyled. Extends the
existing .speaker-label rule rather than duplicating it.
Bumps style.css to v=7 everywhere — the file changed, and pages referenced a
mix of v=5 and v=6, so some visitors would have kept a cached copy without the
new rules.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A --resume run rebuilt the episode title from the Castopod URL slug, which is
lowercased and stripped of punctuation, so episode 58 went to YouTube as
"Episode 58: Rayfield S Nephew The Marfa Lights And Why Nobody Believes Concho"
with a placeholder description. save_chapters() only persisted chapters, so
resume had no real metadata to fall back on.
Metadata is now written to <audio>.metadata.json during a normal run and read
back on resume. If that file is missing (episodes published before this change)
the title and description are read from Castopod instead. Slug reconstruction
survives only as a last resort: it warns loudly, flags the result, and anchors
the episode prefix strip so it no longer eats the phrase mid-title.
Reading back from Castopod needed its own fix — TO_BASE64 wraps every 76 chars
and mysql renders those breaks as a literal backslash-n, which made b64decode
throw and the lookup silently return None.
Also includes two changes that were already sitting in the working tree: the
YouTube tag budget fix that episode 58's invalidTags failure prompted (with its
test), and a metadata model bump to claude-haiku-4.5.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- Add CallRecord dataclass for tracking call history
- Extend Session with call_history, active_real_caller, ai_respond_mode, auto_followup
- Add get_show_history() for AI caller context about earlier calls
- Update get_conversation_summary() to handle host/real_caller/ai_caller roles
- Update reset() to clear new fields
- Add tests for all new functionality
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>