- Make the immediate-backfill guard SYMMETRIC: run_deep_backfill now also registers the channel it pages in _backfill_in_progress, so it and backfill_channel_now mutually exclude per-channel and never advance the same cursor concurrently (whichever started first). The interactive cap moves to a separate _immediate_running counter so the scheduler's channels don't false-trip it. - Attribute the immediate backfill's spend: wrap it in quota.attribute(user_id, VIDEOS_BACKFILL_FULL) (route passes user.id), so it shows under the user's full-backfill action, not the OTHER/system bucket. - Tests: the update_channel->background-task wiring + the demo guard (scheduled for a real user, NOT for demo); distinct N/S/L counts (2 short + 1 live) so a short/live swap fails; extracted channelDetailPollMs with a pure unit test of the poll-or-stop predicate. - a11y: role="img" on the fully-synced charm so screen readers announce it.
9 lines
577 B
TypeScript
9 lines
577 B
TypeScript
import { type ChannelDetail } from "./api";
|
|
|
|
/** How often the channel page re-polls its detail (via useLiveQuery): every 4s while THIS user's
|
|
* full-history backfill is running (`deep_requested && !backfill_done`) so the stored count + the
|
|
* N/S/L breakdown climb on their own, and `false` (stop polling) once the back-catalogue is in or
|
|
* the user never requested it. Extracted so the poll-or-stop decision is unit-testable. */
|
|
export const channelDetailPollMs = (d: ChannelDetail | undefined): number | false =>
|
|
d?.deep_requested && !d.backfill_done ? 4000 : false;
|