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>
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/retiredrecord MUST live under this directory, never in an active file; - an
activerecord MUST NOT live under this directory; supersedes/superseded-bykeys 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.