docs(adr): record ADR-020 recency-bounded auto-summarize + sparse honesty
Document the architecture decision behind this bundle: bound auto-summarize to a recency window (refines ADR-018; bounds load against the ADR-014 gate without fetching harder), surface scarcity honestly, and collapse the un-summarized back-catalogue in a single feed. Records the return-nudge as a deliberate non-goal (it would contaminate the Stage-0 unprompted-return signal, ADR-016). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -697,6 +697,52 @@ the supported path.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## ADR-020 — Recency-bounded auto-summarize + honest sparse-state surface
|
||||||
|
|
||||||
|
**Status:** Accepted (2026-06-08). **Refines ADR-018** (auto-summarize) and **ADR-014**
|
||||||
|
(per-IP caption rate gate).
|
||||||
|
|
||||||
|
**Context.** Tapir is operational but sparse: at real subscription volume the maintainer's
|
||||||
|
account holds ~283 discovered videos, ~15 summarized, ~256 behind the respected per-IP caption
|
||||||
|
rate gate, ~12 no-captions. Two problems follow. (1) **Load:** ADR-018 auto-summarizes *every*
|
||||||
|
unseen video, so a large back-catalogue re-drives the whole queue through the gate every cycle —
|
||||||
|
self-inflicted 429s with no user value (nobody is waiting on a 6-month-old video). (2) **First
|
||||||
|
contact:** a new user sees a mostly-empty feed with no moving parts and a UI that implied
|
||||||
|
abundance/imminence ("fetching soon" ×256, "Run `tapir run`", "Summarize now"); the Stage-0 gate
|
||||||
|
is *return usage*, and the experience died at the first visit. Source: a UX heuristic review
|
||||||
|
(`docs/ux-review/UX-REVIEW-stage0-recency.md`).
|
||||||
|
|
||||||
|
**Decision.**
|
||||||
|
1. **Recency bound on auto-summarize.** In automatic mode the scheduler only summarizes videos
|
||||||
|
published within `TAPIR_AUTO_SUMMARIZE_WINDOW` (default ~7d). Older videos are still discovered
|
||||||
|
and listed but not auto-processed — they keep the manual "Summarize" affordance. An explicit
|
||||||
|
manual request bypasses the bound. `0` disables it (pre-recency behaviour). This bounds auto
|
||||||
|
*load*; it does not fetch harder — the gate (ADR-014) is untouched and the manual path still
|
||||||
|
serialises through it.
|
||||||
|
2. **Honest sparse-state surface.** Copy is reframed to surface scarcity truthfully, never to
|
||||||
|
look fuller: "N ready · M in queue · K no captions" (not "fetching soon"); a one-line "captions
|
||||||
|
are fetched slowly on purpose" note; "Summarize" (not "Summarize now"); the empty-connected
|
||||||
|
state stops printing an impossible CLI command.
|
||||||
|
3. **Feed IA = one list, noise-collapsed.** Summarized + recent un-summarized cards lead inline;
|
||||||
|
the older un-summarized back-catalogue collapses behind a single "Show N older videos"
|
||||||
|
disclosure; caption-less videos collapse to a one-line count instead of N dead cards. List is
|
||||||
|
ordered summarized-first, then `published_at DESC NULLS LAST`.
|
||||||
|
|
||||||
|
**Consequences.** The auto path's per-cycle fetch volume is bounded by recent uploads, not the
|
||||||
|
whole back-catalogue, so steady-state 429 pressure drops sharply. Older videos become explicitly
|
||||||
|
on-demand — a deliberate honesty trade (the user chooses to spend a scarce fetch on old content).
|
||||||
|
The single-replica assumption (ADR-018) is unchanged.
|
||||||
|
|
||||||
|
**Deliberately NOT done (premature until the Stage-0 loop is validated).** Return-nudges
|
||||||
|
(digest email / push) — a nudge contaminates the *unprompted*-return signal the gate measures
|
||||||
|
(ADR-016); building it now poisons the experiment. Also deferred: full-text search, channel
|
||||||
|
facets, read/unread, saved views — all need summary abundance to matter.
|
||||||
|
|
||||||
|
**Reversibility.** `TAPIR_AUTO_SUMMARIZE_WINDOW=0` restores summarize-every-unseen; the feed
|
||||||
|
collapse keys off the same window (`App.RecencyWindow=0` → everything inline).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Rejected alternatives
|
## Rejected alternatives
|
||||||
|
|
||||||
Approaches considered during the 2026-06-02 planning + grill session and **deliberately not
|
Approaches considered during the 2026-06-02 planning + grill session and **deliberately not
|
||||||
|
|||||||
Reference in New Issue
Block a user