Generate the episode page after publishing, not before

regenerate_website_pages() ran at step 3.7, before the step-4 publish call.
generate_episode_pages.py is driven entirely by the RSS feed, so the episode
being published was never in the data it read: the generator exited 0, printed
its success line, and silently omitted the new episode. Its page only appeared
on the NEXT publish.

Social posts link to /episode/<slug>/, so every launch-day link across X,
Bluesky, Discord, Instagram, Threads, Facebook, LinkedIn, Mastodon and Nostr
404'd during exactly the window the post was circulating. That held for all 58
published episodes.

The existing test only asserted the generator gets invoked with --sitemap,
which passed throughout. Added two tests pinning the call between the publish
and the wrangler deploy, verified to fail against the previous ordering.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-15 17:05:17 -05:00
co-authored by Claude Opus 5
parent fe37c037d4
commit 242eb15e0a
2 changed files with 45 additions and 4 deletions
+9 -4
View File
@@ -1871,10 +1871,6 @@ def main():
shutil.copy2(str(transcript_path), str(website_transcript_path)) shutil.copy2(str(transcript_path), str(website_transcript_path))
print(f" Transcript copied to website/transcripts/") print(f" Transcript copied to website/transcripts/")
# Build this episode's static page and regenerate the sitemap wholesale.
# generate_episode_pages.py is the only writer of sitemap.xml.
regenerate_website_pages()
# Sync any remaining episode media to BunnyCDN (cover art, etc.) # Sync any remaining episode media to BunnyCDN (cover art, etc.)
print(" Syncing remaining episode media to CDN...") print(" Syncing remaining episode media to CDN...")
sync_episode_media_to_bunny(episode["id"], uploaded_keys) sync_episode_media_to_bunny(episode["id"], uploaded_keys)
@@ -1891,6 +1887,15 @@ def main():
else: else:
raise raise
# Build this episode's static page and regenerate the sitemap wholesale.
# generate_episode_pages.py is the only writer of sitemap.xml.
#
# MUST run after the publish above: the generator is driven entirely by the
# RSS feed, so running it earlier silently omits the episode being published
# and its page only appears on the NEXT publish. Social posts link to
# /episode/<slug>/, so that left every launch-day link 404ing.
regenerate_website_pages()
# Step 5: Deploy website (transcript + sitemap must be live before social links go out) # Step 5: Deploy website (transcript + sitemap must be live before social links go out)
print("[5/5] Deploying website...") print("[5/5] Deploying website...")
project_dir = Path(__file__).parent project_dir = Path(__file__).parent
+36
View File
@@ -78,3 +78,39 @@ def test_publish_flow_calls_it_after_copying_the_transcript():
copy_at = source.index("Transcript copied to website/transcripts/") copy_at = source.index("Transcript copied to website/transcripts/")
call_at = source.index("regenerate_website_pages()", copy_at) call_at = source.index("regenerate_website_pages()", copy_at)
assert call_at > copy_at assert call_at > copy_at
def test_generator_runs_after_the_publish_call():
"""Ordering regression guard.
generate_episode_pages.py is driven entirely by the RSS feed, so it only
sees an episode once Castopod has published it. For 58 episodes the
regenerate call sat at step 3.7 — before the step-4 publish — so the
episode being published was silently absent from its own run and its page
only appeared on the NEXT publish. Social posts link to /episode/<slug>/,
so every launch-day link 404'd.
Asserted on source order because the surrounding publish flow does network
and filesystem work that isn't practical to drive end to end here.
"""
src = Path(publish_episode.__file__).read_text()
body = src[src.index("def main("):]
publish_call = body.index("published = publish_episode(")
regen_call = body.index("regenerate_website_pages()")
deploy_call = body.index("wrangler")
assert publish_call < regen_call, (
"regenerate_website_pages() must run AFTER publish_episode(), or the new "
"episode is missing from the feed the generator reads"
)
assert regen_call < deploy_call, (
"regenerate_website_pages() must run BEFORE the wrangler deploy, or the "
"freshly built page never ships"
)
def test_regenerate_is_called_exactly_once_in_main():
src = Path(publish_episode.__file__).read_text()
body = src[src.index("def main("):]
assert body.count("regenerate_website_pages()") == 1