Files
ersatztv/docs/decisions/archive
timothyandClaude Opus 5 fad6805b91 feat(651): media-library pickers resolve by search instead of a bounded window
The three `getLibraryBrowseItems` pickers (RerunCollectionsScreen, PlaylistsScreen,
FillerPresetsScreen) populated a native <select> from a 100-row window over media-library
tables that can hold tens of thousands of rows. #644 made that truncation visible; it did
not make the picker usable, and paging to completeness would have been worse than the bug
(~200 serial requests, each more expensive than the last).

They now resolve by SEARCH through the shared `SearchPicker` over a new
`searchLibraryPickerOptions` helper: zero requests on mount or on a type switch, at most ONE
bounded request (25 rows) per settled query, nothing below 2 characters. Typed text is
compiled via the now-shared `titleContainsQuery` (`title:*<escaped>*`) rather than forwarded
raw, since the index's default field does not match bare title words. The current selection
renders from the owning record — `selectedName` for rerun collections and playlist items, and
for filler presets (which store only an id) a single by-id detail read — so editing an
existing record can never lose or fail to name its selection.

Class A stays put: bounded-by-construction admin lists still page to completeness via
`loadAllPages`, and the collection-family filler-preset types keep their bounded single page
(their `query` is a SQL LIKE, which a compiled Lucene query would not match). No server-side
cap is raised; this is a web-only change.

Folded in from #578: the rule-builder facet typeahead arms on focus rather than on mount (an
N-rule tree fired N unrequested lookups), both typeaheads pair their `seqRef` guard with a
shared `useIsMountedRef`, and the roundtrip test's LCG divides by 2^32 so `pick()` can no
longer index one past the end.

Decision record `spa.list-completeness-vs-bounded-pickers` is archived as superseded by the
new `spa.library-pickers-resolve-by-search`; spa-conventions §3b rewritten to match.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 04:25:14 +02:00
..

Archive — superseded / retired decision records

This directory holds decision records whose status is superseded or retired. They are kept verbatim (rationale prose untouched — see docs/decisions.md header and scripts/decisions_lib.py) for history: why we changed our mind is the point, never silently rewritten.

They are out of the active startup path: scripts/decisions_lib.py active_files() / all_active_records() do not glob this directory, docs/decisions/README.md (the active catalog) never lists a record from here, and an agent doing task-router discovery should not need to read this directory to find the current rule — follow a record's superseded-by key to the active successor instead.

The lifecycle validator (scripts/decisions_validate.py) still enforces invariants here:

  • a superseded/retired record MUST live under this directory, never in an active file;
  • an active record MUST NOT live under this directory;
  • supersedes/superseded-by keys must resolve reciprocally to a record in the active set OR here;
  • a record moved here must not have its rationale prose changed in the same commit (unless the commit message carries the [decisions-edit] token, reserved for genuine rationale edits).

One file per topic cluster (e.g. ci.md, release-ci-governance.md), mirroring the active docs/decisions/*.md topic-file split. See docs/decisions/migration-map.md for the legacy heading → key → status → location mapping produced during the #521 lifecycle migration.