From 2cda62b3adab7fe18783b04ff27692de5bdec87c Mon Sep 17 00:00:00 2001 From: Mathias Date: Mon, 8 Jun 2026 14:04:37 +0200 Subject: [PATCH] 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) --- DECISIONS.md | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/DECISIONS.md b/DECISIONS.md index 909bfeb..4218f4c 100644 --- a/DECISIONS.md +++ b/DECISIONS.md @@ -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 Approaches considered during the 2026-06-02 planning + grill session and **deliberately not