diff --git a/sql/127-news-future-date-guard.sql b/sql/127-news-future-date-guard.sql new file mode 100644 index 0000000..2af3b72 --- /dev/null +++ b/sql/127-news-future-date-guard.sql @@ -0,0 +1,32 @@ +-- sql/127-news-future-date-guard.sql +-- News published_at cannot be in the future: an article cannot be published after +-- we scraped it. One future-dated row found 2026-07-06 (The Next Platform, pub +-- 2026-07-15 but created/scraped 2026-06-19). One-time correction + ingest guard so +-- it cannot recur (a CHECK with now() is not immutable/allowed -> BEFORE trigger). +-- Idempotent; safe to re-run. + +-- One-time: clamp any future published_at to the scrape date (created_at), else now(). +update news_articles + set published_at = least(published_at, coalesce(created_at, now())) + where published_at is not null and published_at > now(); + +create or replace function news_published_at_guard() returns trigger +language plpgsql as $$ +begin + if NEW.published_at is not null and NEW.published_at > now() then + NEW.published_at := least(coalesce(NEW.created_at, now()), now()); + end if; + return NEW; +end $$; + +comment on function news_published_at_guard() is + 'BEFORE INSERT/UPDATE on news_articles: clamps a future published_at to the scrape date (created_at) or now(). Prevents future-dated news polluting the feed.'; + +drop trigger if exists trg_news_published_at_guard on news_articles; +create trigger trg_news_published_at_guard + before insert or update on news_articles + for each row execute function news_published_at_guard(); + +insert into _migrations (filename, applied_at) +select '127-news-future-date-guard.sql', now() +where not exists (select 1 from _migrations where filename = '127-news-future-date-guard.sql');