feat(discovery): per-channel caption-availability memory (ADR-024)
After transcript caching (ADR-021) and the Shorts filter (ADR-023), the remaining caption waste is the first fetch on every new video of a channel that never has English captions — each costs one rate-limited fetch to resolve to "none", and on a throttled IP churns the backoff machinery first. Remember, per (user, channel), a streak of consecutive no-caption outcomes (channel_caption_state, migration 016, RLS-scoped). Once it reaches TAPIR_CHANNEL_CAPTIONLESS_THRESHOLD (default 5) the channel is suppressed — videos discovered/listed but not caption-fetched — for TAPIR_CHANNEL_CAPTIONLESS_WINDOW (default 14d), then one is re-probed (auto-recovery). A successful fetch resets the streak; a 429 does not count; an explicit manual request bypasses suppression. threshold=0 disables. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -891,6 +891,38 @@ this is well under the 10k/day cap; at larger scale, batch `videos.list` across
|
||||
|
||||
---
|
||||
|
||||
## ADR-024 — Per-channel caption-availability memory
|
||||
|
||||
**Status:** Accepted (2026-06-10). **Builds on ADR-014** (per-IP caption budget), **ADR-021**
|
||||
(shared transcript cache), **ADR-023** (Shorts filter).
|
||||
|
||||
**Context.** After ADR-021 caches transcripts and ADR-023 drops Shorts, the remaining caption
|
||||
waste is the *first* fetch on every new video of a channel that never publishes English captions
|
||||
(foreign-language news, music, etc.). Each costs one rate-limited fetch to resolve to "none" —
|
||||
and on a throttled IP that fetch may 429 and churn the backoff machinery before it ever gets a
|
||||
verdict. A pilot user's feed had several such channels.
|
||||
|
||||
**Decision.** Remember, per `(user, channel)`, a streak of consecutive no-caption outcomes
|
||||
(`channel_caption_state`, migration 016, RLS-scoped like the rest of the user-owned schema).
|
||||
Once the streak reaches `TAPIR_CHANNEL_CAPTIONLESS_THRESHOLD` (default 5) the channel is
|
||||
suppressed — its videos are discovered/listed but not caption-fetched — for
|
||||
`TAPIR_CHANNEL_CAPTIONLESS_WINDOW` (default 14d), after which one video is re-probed
|
||||
(auto-recovery for a channel that starts adding captions). A successful fetch resets the streak;
|
||||
a fresh 429 does NOT count (transient, not a caption verdict). An explicit manual request
|
||||
bypasses suppression. `threshold = 0` disables the feature.
|
||||
|
||||
**Why per-user, not global.** Caption availability is really a channel property (public), so a
|
||||
global table would let users share the learning. But subscriptions are per-user (ADR-012) and at
|
||||
pilot scale users' channel sets barely overlap, so per-user + RLS keeps it consistent with the
|
||||
existing isolation model with no new non-RLS exception to justify. Promoting to a shared table
|
||||
(like transcripts, ADR-021) is a future optimisation if channel overlap grows.
|
||||
|
||||
**Reversibility.** Migration 016 is a clean drop; `threshold = 0` disables at runtime. The
|
||||
memory only ever *suppresses fetches* — it never deletes content or affects already-stored
|
||||
summaries.
|
||||
|
||||
---
|
||||
|
||||
## Rejected alternatives
|
||||
|
||||
Approaches considered during the 2026-06-02 planning + grill session and **deliberately not
|
||||
|
||||
Reference in New Issue
Block a user