Make the Confluence "Promo Calendar" page the single source of truth for
MuseHub partner campaign promos, and reshape the promo data layer around a
clear superset/subset split:
- promos (umbrella) = campaigns (Confluence-sourced, time-boxed) + first-party
(hand-authored, evergreen).
- `bun run pull-campaigns` (scripts/pull-campaigns.ts) fetches the page,
deterministically extracts the calendar table (URLs preserved verbatim),
resolves year-less date ranges, keeps only active/upcoming promos, maps them
to typed PromoData, validates every emitted URL traces back to source, and
writes src/assets/data/promos/campaigns.ts. Opt-in --clean-copy runs an LLM
pass that may only tidy copy text. Never commits or pushes.
- Site-owned promos (audio.com exit popup, Audacity 4 alpha/video, survey) move
to src/assets/data/promos/firstParty.ts.
- Delete legacy banners.ts / videos.ts / popups.ts; promotions.ts now merges
firstParty + campaign promos only.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>