Files
tapir/docs/specs/newest-first-ordering.md
T
mathiasandClaude Opus 4.8 27fd33c99c
CI / Lint / Test / Vet (push) Successful in 11s
CI / Build & Import (push) Successful in 10s
docs: reconcile requirements + architecture with ADR-020
Bring the living docs current with the recency-bounded auto-summarize + sparse
honesty + feed IA bundle (ADR-020):

- requirements (BDD): summarize_mode.feature — auto now summarizes RECENT new
  videos; added a scenario for older videos (listed, on-demand), recency note.
- architecture.md: summarization-mode + new list-surface paragraph; scheduler
  diagram + two-path table + three-phase pass now show the recency pre-filter;
  dropped stale "Summarize now".
- data-model.md: auto_summarize is recent-only, older on-demand.
- README.md: one-line recency note on the serve scheduler.
- ui-spec.md: appended the as-built ADR-020 row (supersedes earlier copy/sort).
- specs/{video-card-states,newest-first-ordering,scheduled-discovery}.md:
  superseded/extended banners pointing at ADR-020 (kept as design records).

Docs-only; task check green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 20:21:14 +02:00

5.1 KiB

Spec — Newest-first batch ordering + honest "Try now" / prioritisation docs

Extended by ADR-020 (2026-06-08). This spec covers the batch processing order within a pass. ADR-020 adds (a) a recency pre-filter — auto mode skips videos published before TAPIR_AUTO_SUMMARIZE_WINDOW, listed but summarised on demand — and (b) the same published_at DESC NULLS LAST ordering on the list read (ListVideos), which previously sorted by seen_at. See DECISIONS.md ADR-020.

Repo: tapir · Size: small · Solo session.

Why. Product intent (maintainer, 2026-06-06): a new user should get summaries of their newest videos quickly, while the older back-catalogue fills in behind — all within the one shared rate gate. Today the foreground path ("Try now" button) lets a user hand-pick a video, but the background batch processes in subscription/channel order, not newest-first — so a new user with a large candidate set sees the batch summarise whatever channel is first in their subscription list, not their newest videos. This slice makes the batch agree with the intent, and fixes the docs to describe the real rationale (onboarding prioritisation), not the traffic-disguising framing a prior session wrote.

Read CLAUDE.md + DECISIONS.md (ADR-014, ADR-018) first. TBD, conventional commits, task check green per commit, templ generate if views change.

1. Newest-first batch ordering (the build)

In internal/runner/runner.go RunOnce: today the loop processes each video inline while walking subscriptions channel-by-channel (for sub → NewVideos → for v → process). Change so that, within a pass, candidates are processed newest-first across ALL channels:

  • Collect the candidate videos across channels first (after dedup/seen/manual/rate-limit filtering as today), then sort by published_at descending before processing, then process in that order through the engine + shared globalFetchGate.
  • published_at is nullable (schema 001). Sort NULLS LAST — videos with no publish date must not jump ahead of dated newest videos. Decide a stable tiebreak (e.g. seen_at DESC) for equal/again-null dates.
  • Keep all existing behaviour: per-item failure isolation, the rate-limit backoff skip, manual mode, channel-unavailable handling, stats. Ordering is the only change — not what gets processed, just the order.
  • At 868 candidates a collect-then-sort in memory is fine; do not build a streaming/external sort. Keep it simple.
  • The shared rate gate (globalFetchGate) is unchanged and still governs fetch pacing — ordering does not bypass or weaken it.

Optional (only if cheap and clearly correct): a soft cap so the first pass for a brand-new user summarises the newest N (e.g. 20) quickly and defers the long tail to subsequent passes — so onboarding value lands fast without waiting for the whole sorted set. If this adds real complexity, SKIP it and just do the newest-first ordering; the ordering alone delivers the intent.

2. Tests

  • Given candidates across multiple channels with mixed published_at (incl. some NULL), assert the processing order is newest-first, NULLS LAST, with the chosen tiebreak. Use the existing fake VideoStore/Processor pattern in runner_test.go.
  • Assert ordering does not change which videos are processed vs. today (same set, new order).
  • Rate-gate / backoff / manual-mode behaviour unchanged (existing tests stay green).

3. Docs — describe the REAL rationale (replace prior framing)

The "Try now" button and the discovery batch together implement onboarding prioritisation: foreground (user-clicked "Try now") summarises a specific video on demand; background batch summarises newest-first; both honour the shared rate gate. Update the docs to state this intent — and explicitly REMOVE/replace any framing that describes "Try now" as making traffic "look organic to YouTube" or evading rate limits. That is not the rationale. The rationale is: get the user a few summaries of their newest, most relevant videos fast; process the back-catalogue in the background; always within the honest shared rate limit. Rate limiting is respected, not evaded.

  • docs/ui-spec.md: "Try now" = on-demand foreground summarisation of a chosen (typically newer) video; rationale = fast onboarding value, not traffic shaping.
  • docs/architecture/architecture.md: document the two-path model — foreground on-demand vs. background newest-first batch, both through globalFetchGate — and the newest-first ordering.
  • Any requirements/use-case doc mentioning discovery order: state newest-first.
  • If a brain note or wiki entry captured the "looks organic" rationale, correct it there too.

Boundaries

  • Do NOT increase fetch rate or weaken the rate gate. Account-safety constraint stands: the caption endpoint is unofficial (ADR-010) and must be treated with honest backoff, never evasion.
  • Do NOT touch RLS, credentials, or the Dex surface.
  • Ordering change is within a pass only — no persisted priority queue, no new table.

Out of scope

Per-user configurable ordering; priority weighting beyond newest-first; the soft-cap if it proves non-trivial.