A self-contained `src/library/pools.ts`: a generic `BoundedPool` concurrency
limiter and a `RequestPools` bundle of three at the design's caps (metadata 10,
content 5, thumbnails 25, each overridable). Within a pool, on-demand work is
served before background/precache work, first-come-first-served within a
priority; a task submitted under a `key` already pending is shared rather than
run twice, and the key frees the moment that task settles. The slot is held for
the task's whole lifetime, so a request that retries internally stays counted
against the cap between attempts.
Pools only; nothing wires them into `Library` yet — that is a later unit.
Model: opus-4-8
Library.open loads metadata.json and serves reads from RAM: an empty cache awaits the first refresh, an existing cache returns at once and refreshes in the background so an unreachable server never stalls open(). A background timer refreshes every refreshIntervalSeconds (default 3), diffing only changed albums via the resumable cursor+tombstone enumerators and rewriting metadata.json only when something changed. A refresh failure is invisible to reads and surfaced via status()/onProgress; a failed save keeps status().lastError set and retries until one lands, so a stale disk is never masked. No sync()/refresh()/serverReachable surface; status() and close() included.
Model: opus-4-8
Adds the metadata.json store: loads whole into RAM with id-lookup Maps, rewrites whole through the exported fsync atomic writer (temp, fsync, rename, dir fsync); a missing, unparseable, or wrong-schema file loads as empty (it is a cache); directory 0700, file 0600. No lock file, no public sync().
Model: opus-4-8