Update (2026-06-22) — the feed is not truncated to 10 items. When the sync was actually built, the live feed (
feed.podbean.com/powershellpodcast/feed.xml) returned the complete archive (234 items, all of The PowerShell Podcast), not the 10-item window assumed below. This does not change the chosen design — the sync is add-only and never reconciles or deletes, so a full pass over the feed is safe — but it has three consequences:
- The one-time backfill (WS3) is subsumed by the first sync run. Because the feed carries eps 221–234, the first run of the Action generated them directly; no separate YouTube/Podbean scrape was needed.
- The idempotency key is the enclosure URL, not the episode number. Every existing modern file carries the enclosure as
podcast_url; none carried aguid. Matching is enclosure-URL →guid→episode, in that order.itunes:episodeis unreliable — it runs one ahead of the repo's convention, which parses the episode number from the Podbean enclosure filename (..._episode_NNN_...). The sync derivesepisodefrom the filename to stay consistent with the existing 217 numbered files, usingitunes:episodeonly to disambiguate the rare filename whose number has a glued-on suffix (episode_2298xv9d).The truncation-driven cadence concern below is now a safety margin rather than a hard constraint: even a long outage would not lose episodes while the feed carries the full archive. The cadence is still kept weekly so the section stays fresh and the add-only diffs stay small. The anti-reconcile rule still stands — the Action must never widen into a delete/reconcile pass.
[[The PowerShell Podcast]] is kept in step with the repo from its Podbean RSS feed
(feed.podbean.com/powershellpodcast/feed.xml). The non-obvious constraint that shapes
the whole design: the feed is truncated to the 10 most recent items. It is a
notification of recent episodes, not an archive. The 220 modern episodes already in
content/podcast/ were migrated from elsewhere, not fetched from this feed, and the feed
cannot reproduce them.
We therefore treat sync as incremental tail maintenance, not a feed-driven rebuild. A
scheduled GitHub Action (weekly, mirroring discourse-sync.yml) fetches the feed and
adds episodes it hasn't seen, matching existing files by guid and falling back to the
episode number parsed from the podcast_url filename. It never rebuilds or reconciles
the back catalogue against the feed, because the feed does not contain it.
History that predates the current 10-item window is handled once, out-of-band: episodes 221–224 (already rolled off the feed before the first sync) are backfilled from the YouTube playlist / Podbean website, and the existing archive is enriched in place. This is a deliberate split — the ongoing automation owns only the recent tail.
- Treat the feed as the source of truth and reconcile the section against it — rejected. With only 10 items visible, every run would see 210+ "missing" episodes and either do nothing useful or, worse, delete the archive. The feed simply does not carry enough to be authoritative.
- Scrape the full Podbean website archive (~24 pages) on every run — rejected for the steady state. It removes the truncation limit but is brittle (HTML scraping), slow, and unnecessary when the feed already announces new episodes reliably. We use a scrape once for backfill, where its cost is paid a single time.
- Incremental RSS tail + one-time backfill — chosen. The feed does exactly what it is good at (announcing new episodes); scraping is confined to the one-time historical gap; steady-state sync stays simple and cheap.
- Cadence is load-bearing. The Action must run often enough that no episode is published and then rolls off the 10-item window between runs. At a weekly release cadence that is ~10 weeks of slack; weekly runs leave a wide margin. If the schedule is disabled or the Action is broken for a long stretch, episodes can be permanently lost from sync and will need the same out-of-band backfill that 221–224 required. This is the failure mode to watch.
- The matched-by-
guid-then-episoderule means old episodes never need a real RSSguidstored — they will never re-appear in the feed to be matched.guidis recorded only for episodes seen through the feed;episode(from thepodcast_urlfilename) is the universal key. See [[Author]] for how authorship is set on synced episodes (author: Andrew Pla, guests appended conservatively). - Backfill and ongoing sync are different code paths with different trust levels: the scrape is a reviewed one-shot; the Action auto-commits. Because there is no review gate on the Action, guest extraction is conservative (high-confidence additions only, never removals) so a bad parse degrades to a missing guest, not a wrong byline.
- A future maintainer must not "fix" the sync by widening it into a full reconcile against the feed — that path is closed by the truncation and is why this record exists.