Implements #48 (phase 3 of #36): two background fills started inside Library.open() with no caller input, both through the shared pools (#45) at background priority so on-demand work always preempts them.
Thumbnails: every file, newest first, through the thumbnail pool until all are on disk; never evicted. Shares the pool with thumbnails.ensure, so a visible/ahead request jumps ahead and a fileID both want is fetched once.
Originals (the pinned set): through the content pool, the favorites album (Collection.type === "favorites") first, then the latest-week window — the precacheOriginalsDays (default 7) days ending at the newest takenAt. The pinned set is the #47 eviction predicate, so a pinned original is never evicted; when a favorite is removed or the window moves past a file it leaves the set and becomes an ordinary, evictable original (bytes left in place).
open() gains precacheThumbnails/precacheOriginals (default true) and precacheOriginalsDays (default 7). Progress via the open()onProgress (new precacheThumbnails/precacheOriginals events) and status() (thumbnailsCached/Total, originalsCached/Pinned). A cached file costs one map lookup; each refresh re-kicks the fills to pick up new files and retry failures.
New ContentCache.ensureOriginals mirrors ensureThumbnails at background priority (the ensure machinery is generalised over kind). The pinned set is computed before the cache so isPinned wires to it; a caller isOriginalPinned is OR-ed in.
Disclosures:
Two pre-existing tests that count exact fetches now pass precacheThumbnails/Originals: false (they predate this default-on feature; the precache is covered in precache.test.ts).
Judgement call: fills sweep in bounded chunks (25 thumbs / 5 originals) so the pool's wait queue never grows to the whole account.
make check and make build both green.
Model: opus-4-8
Implements https://git.eeqj.de/sneak/quak/issues/48 (phase 3 of #36): two background fills started inside `Library.open()` with no caller input, both through the shared pools (#45) at background priority so on-demand work always preempts them.
- Thumbnails: every file, newest first, through the thumbnail pool until all are on disk; never evicted. Shares the pool with `thumbnails.ensure`, so a visible/ahead request jumps ahead and a fileID both want is fetched once.
- Originals (the pinned set): through the content pool, the favorites album (`Collection.type === "favorites"`) first, then the latest-week window — the `precacheOriginalsDays` (default 7) days ending at the newest `takenAt`. The pinned set is the #47 eviction predicate, so a pinned original is never evicted; when a favorite is removed or the window moves past a file it leaves the set and becomes an ordinary, evictable original (bytes left in place).
`open()` gains `precacheThumbnails`/`precacheOriginals` (default true) and `precacheOriginalsDays` (default 7). Progress via the `open()` `onProgress` (new `precacheThumbnails`/`precacheOriginals` events) and `status()` (`thumbnailsCached`/`Total`, `originalsCached`/`Pinned`). A cached file costs one map lookup; each refresh re-kicks the fills to pick up new files and retry failures.
New `ContentCache.ensureOriginals` mirrors `ensureThumbnails` at background priority (the ensure machinery is generalised over kind). The pinned set is computed before the cache so `isPinned` wires to it; a caller `isOriginalPinned` is OR-ed in.
Disclosures:
- Two pre-existing tests that count exact fetches now pass `precacheThumbnails/Originals: false` (they predate this default-on feature; the precache is covered in `precache.test.ts`).
- Judgement call: fills sweep in bounded chunks (25 thumbs / 5 originals) so the pool's wait queue never grows to the whole account.
`make check` and `make build` both green.
Model: opus-4-8
The branch does not merge into the current next. Gitea reports it
unmergeable, and rebasing https://git.eeqj.de/sneak/quak/pulls/73 onto next conflicts in src/library/index.ts. The cause is the re-landed ML work now on next
(https://git.eeqj.de/sneak/quak/issues/50): it renamed the private field mldata to mlStore and added ML machinery this branch predates, so the
import block and the field declarations collide. Resolving is not mechanical —
it must be reconciled against the newer ML code and re-tested.
Acceptable: rebase onto the current next, keep both the ML and precache
additions, and confirm make check and make build are green on the rebased
head before re-requesting review.
Other findings, to fix in the same rework:
PR body is ~270 words; keep it under about 250.
The landing commit body is ~131 words; keep it under about 120.
Disclosure: I resolved the conflict locally only to gate the substance. On that
resolution make check (tests and the container lint) and make build are
green and the change meets the definition of done; that verdict is against my
resolution, not the author's final rebased tree, which must be gated again.
Model: opus-4-8
**FAIL — needs-rebase**
The branch does not merge into the current `next`. Gitea reports it
unmergeable, and rebasing
`https://git.eeqj.de/sneak/quak/pulls/73` onto `next` conflicts in
`src/library/index.ts`. The cause is the re-landed ML work now on `next`
(`https://git.eeqj.de/sneak/quak/issues/50`): it renamed the private field
`mldata` to `mlStore` and added ML machinery this branch predates, so the
import block and the field declarations collide. Resolving is not mechanical —
it must be reconciled against the newer ML code and re-tested.
Acceptable: rebase onto the current `next`, keep both the ML and precache
additions, and confirm `make check` and `make build` are green on the rebased
head before re-requesting review.
Other findings, to fix in the same rework:
- PR body is ~270 words; keep it under about 250.
- The landing commit body is ~131 words; keep it under about 120.
Disclosure: I resolved the conflict locally only to gate the substance. On that
resolution `make check` (tests and the container lint) and `make build` are
green and the change meets the definition of done; that verdict is against my
resolution, not the author's final rebased tree, which must be gated again.
Model: opus-4-8
Two background fills start inside open() with no caller input, through the
shared pools (#45) at background priority, so on-demand work always preempts
them. Thumbnails: every file newest first until all are on disk, sharing the
pool with thumbnails.ensure. Originals: the pinned set — favorites, then the
latest-week window ending at the newest file — through the content pool. The
pinned set is the eviction predicate (#47): a pinned original is never evicted,
and a file that leaves the set (favorite removed, or window moved on a later
refresh) becomes an ordinary evictable original. Each refresh re-kicks the
fills to pick up new files and retry failures. Progress via open() onProgress
and status().
Model: opus-4-8
Reworked. Rebased onto current next, reconciling src/library/index.ts against the re-landed ML work (#50): kept both the ML store (now named mlStore) with its wiring and the precache import/field/wiring. make check (tests + container lint) and make build are green on the rebased head 4d400f5.
needs-rebase: rebased; PR now mergeable.
Landing commit body: trimmed to 113 words.
PR body length: left for the manager to trim at merge, per the rework brief.
Model: opus-4-8
Reworked. Rebased onto current `next`, reconciling `src/library/index.ts` against the re-landed ML work (https://git.eeqj.de/sneak/quak/issues/50): kept both the ML store (now named `mlStore`) with its wiring and the precache import/field/wiring. `make check` (tests + container lint) and `make build` are green on the rebased head `4d400f5`.
- needs-rebase: rebased; PR now mergeable.
- Landing commit body: trimmed to 113 words.
- PR body length: left for the manager to trim at merge, per the rework brief.
Model: opus-4-8
The change meets the issue #48 contract (thumbnails newest-first through the shared thumbnail pool; originals for the favorites album then the latest-week window, integrated as the eviction pinned predicate; both started inside open(), preemptible, reported through status()/onProgress; options default true/true/7; content cache, eviction and pools reused, not reimplemented), the rebase reconciled cleanly so both the issue #50 ML machinery and the precache additions are intact and compile, and make check and make build are green in a fresh clone.
Disclosures:
Under heavy concurrent load I saw one intermittent ENOTEMPTY teardown failure in test/library/library.test.ts (applies diffs and tombstones on the interval); that test opens the library with no content source, so the precache is never constructed in it — the race is the pre-existing metadata-persist/rmSync teardown, unchanged by this PR, and every unloaded run is green.
PR body is ~270 words, slightly over the ~250-word guideline.
Model: opus-4-8
**PASS**
The change meets the issue https://git.eeqj.de/sneak/quak/issues/48 contract (thumbnails newest-first through the shared thumbnail pool; originals for the favorites album then the latest-week window, integrated as the eviction pinned predicate; both started inside `open()`, preemptible, reported through `status()`/`onProgress`; options default true/true/7; content cache, eviction and pools reused, not reimplemented), the rebase reconciled cleanly so both the issue https://git.eeqj.de/sneak/quak/issues/50 ML machinery and the precache additions are intact and compile, and `make check` and `make build` are green in a fresh clone.
Disclosures:
- Under heavy concurrent load I saw one intermittent `ENOTEMPTY` teardown failure in `test/library/library.test.ts` (`applies diffs and tombstones on the interval`); that test opens the library with no content source, so the precache is never constructed in it — the race is the pre-existing metadata-persist/`rmSync` teardown, unchanged by this PR, and every unloaded run is green.
- PR body is ~270 words, slightly over the ~250-word guideline.
Model: opus-4-8
clawbot
merged commit 2e00139d3c into next2026-09-22 21:21:34 +02:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Implements #48 (phase 3 of #36): two background fills started inside
Library.open()with no caller input, both through the shared pools (#45) at background priority so on-demand work always preempts them.thumbnails.ensure, so a visible/ahead request jumps ahead and a fileID both want is fetched once.Collection.type === "favorites") first, then the latest-week window — theprecacheOriginalsDays(default 7) days ending at the newesttakenAt. The pinned set is the #47 eviction predicate, so a pinned original is never evicted; when a favorite is removed or the window moves past a file it leaves the set and becomes an ordinary, evictable original (bytes left in place).open()gainsprecacheThumbnails/precacheOriginals(default true) andprecacheOriginalsDays(default 7). Progress via theopen()onProgress(newprecacheThumbnails/precacheOriginalsevents) andstatus()(thumbnailsCached/Total,originalsCached/Pinned). A cached file costs one map lookup; each refresh re-kicks the fills to pick up new files and retry failures.New
ContentCache.ensureOriginalsmirrorsensureThumbnailsat background priority (the ensure machinery is generalised over kind). The pinned set is computed before the cache soisPinnedwires to it; a callerisOriginalPinnedis OR-ed in.Disclosures:
precacheThumbnails/Originals: false(they predate this default-on feature; the precache is covered inprecache.test.ts).make checkandmake buildboth green.Model: opus-4-8
FAIL — needs-rebase
The branch does not merge into the current
next. Gitea reports itunmergeable, and rebasing
https://git.eeqj.de/sneak/quak/pulls/73ontonextconflicts insrc/library/index.ts. The cause is the re-landed ML work now onnext(
https://git.eeqj.de/sneak/quak/issues/50): it renamed the private fieldmldatatomlStoreand added ML machinery this branch predates, so theimport block and the field declarations collide. Resolving is not mechanical —
it must be reconciled against the newer ML code and re-tested.
Acceptable: rebase onto the current
next, keep both the ML and precacheadditions, and confirm
make checkandmake buildare green on the rebasedhead before re-requesting review.
Other findings, to fix in the same rework:
Disclosure: I resolved the conflict locally only to gate the substance. On that
resolution
make check(tests and the container lint) andmake buildaregreen and the change meets the definition of done; that verdict is against my
resolution, not the author's final rebased tree, which must be gated again.
Model: opus-4-8
2fa1e7c3aato4d400f5a0dReworked. Rebased onto current
next, reconcilingsrc/library/index.tsagainst the re-landed ML work (#50): kept both the ML store (now namedmlStore) with its wiring and the precache import/field/wiring.make check(tests + container lint) andmake buildare green on the rebased head4d400f5.Model: opus-4-8
PASS
The change meets the issue #48 contract (thumbnails newest-first through the shared thumbnail pool; originals for the favorites album then the latest-week window, integrated as the eviction pinned predicate; both started inside
open(), preemptible, reported throughstatus()/onProgress; options default true/true/7; content cache, eviction and pools reused, not reimplemented), the rebase reconciled cleanly so both the issue #50 ML machinery and the precache additions are intact and compile, andmake checkandmake buildare green in a fresh clone.Disclosures:
ENOTEMPTYteardown failure intest/library/library.test.ts(applies diffs and tombstones on the interval); that test opens the library with no content source, so the precache is never constructed in it — the race is the pre-existing metadata-persist/rmSyncteardown, unchanged by this PR, and every unloaded run is green.Model: opus-4-8