-- Migration 016: per-(user, channel) caption-availability memory (ADR-024). -- -- Some channels never publish English captions (foreign-language news, music, -- etc.). Each of their new videos still costs ONE rate-limited caption fetch -- (ADR-014) before resolving to "none" — and on a throttled egress IP that fetch -- may 429 and churn through the backoff machinery first. This table remembers -- channels that repeatedly yield no captions so discovery can stop attempting -- their videos, freeing the scarce fetch budget for channels that do have them. -- -- consecutive_none counts no-caption outcomes in a row; a successful fetch resets -- it to 0. Once it crosses the threshold the channel is suppressed until -- captionless_until, after which one video is re-probed (auto-recovery for a -- channel that starts adding captions). Per-user + RLS-scoped, consistent with -- the rest of the user-owned schema (subscriptions are per-user; ADR-012). CREATE TABLE channel_caption_state ( user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, channel_id TEXT NOT NULL, consecutive_none INT NOT NULL DEFAULT 0, captionless_until TIMESTAMPTZ, updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), PRIMARY KEY (user_id, channel_id) ); CREATE INDEX idx_channel_caption_state_user_id ON channel_caption_state(user_id); ALTER TABLE channel_caption_state ENABLE ROW LEVEL SECURITY; ALTER TABLE channel_caption_state FORCE ROW LEVEL SECURITY; CREATE POLICY channel_caption_state_isolation ON channel_caption_state FOR ALL USING (user_id = current_setting('tapir.current_user_id', true)::uuid);