Commit Graph
8 Commits
Author SHA1 Message Date
peter 8759b5860d test(be): every dependency override goes through override_dep
22 test files set `app.dependency_overrides[...]` by hand and tore down with a blanket `.clear()`
in a `finally`, which wipes every override rather than the test's own and stops fixtures composing.
They now take the `override_dep` fixture (helpers get it passed in), whose teardown restores each
key's prior value; no clear() carried meaning between two phases of a test. A convention test fails
any test file that writes `dependency_overrides` directly.
2026-09-19 17:26:07 +02:00
peter 00527d0cf3 feat(channels): leading '+ Tag' pill + detail-page Unhide affordance (S6)
Item 6 — the tag add-trigger now LEADS the chip row (a stable left anchor)
instead of trailing it, so on the detail page (bounded=false) adding chips
grows the row to its right and the '+'/its editor popover no longer drift.
Compact icon in the width-bounded manager cell; a labelled '+ Tag' pill
where there's free width (the detail header).

Item 7 — surface the per-subscription 'hidden' flag on the detail GET
(channel_detail was omitting it) and add an Eye/EyeOff hide/unhide toggle
next to Block on the channel page, mirroring the manager. FE ChannelDetail
gains 'hidden'; new channel.* i18n keys (HU+EN).

Tests: +3 backend (channel_detail surfaces hidden, both states + unsubscribed
default). Gate green: backend pytest 471, FE vitest 498.
2026-08-27 04:02:25 +02:00
peter b1832afd18 style: apply ruff format across backend + scripts (line-length 100)
Mechanical, whole-tree `ruff format` pass — no behaviour change. Recorded in
.git-blame-ignore-revs (next commit) so git blame skips it.
2026-08-23 07:43:06 +02:00
peter ee2bd81254 test(backfill): lock the per-page durability and reserve-guard properties
Deep-review round 1 found the new tests asserted end-state only, so both
safety mechanisms this change adds were untested (a regression would ship
green):

- Per-page cursor durability: add test_a_mid_run_failure_leaves_the_prior_page
  _durably_committed, which fails the 2nd page's fetch after page 1 committed
  and asserts the cursor + rows are already persisted (re-read via db.expire).
  Mutation-verified: reverting to a single end-of-loop commit makes it fail
  while the pre-existing paging tests stay green — the property the original
  test could not distinguish.
- Reserve guard: add test_backfill_reserve_reached_tracks_the_boundary, driving
  real record_usage spend across the 9000/2000 default boundary and asserting
  the un-mocked quota.backfill_reserve_reached() flips at exactly remaining<=reserve.

Full backend suite: 244 passed, 2 skipped (network-gated).
2026-08-16 03:02:37 +02:00
peter 48285a715b refactor(backfill): centralize the reserve-yield guard and drop the per-page connection hold
Addresses the code-review findings on the immediate full-history change:

- Extract quota.backfill_reserve_reached(): the remaining/reserve compare was
  open-coded at seven sites (recent/deep/immediate backfill, explore, rolling
  revalidation, and the new per-page guard). It reads in its OWN short-lived
  session (like record_usage/log_action), so a per-page guard no longer holds
  the caller's transaction open across the YouTube fetch that follows — the
  400-page immediate run no longer pins a pooled connection idle-in-transaction
  through each network round-trip. Migrated all call sites; dropped the now-dead
  sysconfig imports in channels.py and maintenance.py.
- Simplify the deep-backfill loop: channel.backfill_done = not page_token (done
  is False on entry) plus one break, replacing the doubled `if not page_token`.
- Tests patch the backfill_reserve_reached seam directly instead of mocking
  remaining_today internals, removing the fragile dead-value budget iterator.

Full backend suite green; ruff clean.
2026-08-16 02:41:49 +02:00
peter e3ee1baa94 fix(backfill): finish large channels in one immediate full-history run
The user-triggered "get full history" (backfill_channel_now) capped at
max_pages=60 = 3000 videos. A channel just over that (BBC Earth: 3403
uploads = 69 pages) stopped one page short, so its tail dribbled in over
the scheduler's paced 10-minute ticks (250 videos/tick) and the button
spinner looked stuck for ~18 minutes with no visible progress.

- Raise the immediate cap to max_pages=400 (20 000 videos) so any
  realistic channel completes in the single background run.
- Make a high cap safe: backfill_channel_deep now re-checks the shared
  quota before each page and yields at the backfill reserve (previously
  quota was checked once by the caller before the whole run), and commits
  the advanced cursor after every page so a restart resumes instead of
  re-fetching — and re-charging quota for — pages already stored.
- Channel page: while loading, the button shows the live stored/total
  count and a tooltip explaining the tail finishes in the background, so a
  very large channel's paced remainder reads as progress, not a hang.

Adds deep-backfill paging tests (per-page cursor commit + resume, and the
per-page quota yield).
2026-08-15 17:13:52 +02:00
peter 5720356191 fix(channels): address R14 deep-review findings
- 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.
2026-08-15 07:11:50 +02:00
peter 2cc77757d9 fix(channels): address R14 code-review findings
- list_channels no longer computes the Normal/Shorts/Live aggregation the
  frontend stopped reading when R14 dropped the N/S/L table column; the dead
  ManagedChannel.count_* fields are gone too.
- Immediate "get full history" backfill now coordinates with the paced
  scheduler via a small in-flight set: capped at 2 concurrent + per-channel
  dedup, and run_deep_backfill skips a channel an immediate backfill owns —
  killing the cursor race and bounding the quota-drain burst, without losing
  the speed win.
- Add test_channel_backfill.py: the channelDetail N/S/L counts + the guard's
  no-op / cap / scheduler-skip behaviour.
- Inline the syncedChannels useMemo (its dep is a fresh array each render, so
  it never cached); fix the stale "~2-min ticks" comment (it's 10 minutes).
2026-08-15 06:38:19 +02:00