android: the handoff — the pending rounds, the pipeline, and what is unverified
Everything written this session that has not been through the device: rounds 43 to 48 (each patch adversarially verified, 43's transient-notice expectation fixed), a partial round 49, the pipeline scripts, the Android Auto design and the icon comparison mock. Also the two harness changes that were never A/B'd — adaptive waits, which may only shorten a declared wait and never lengthen it, and a ship that runs the mock walk and the deploy at the same time. The A/B and its 255-step baseline are in handoff/tools; main stays at what the phone has actually walked.
This commit is contained in:
1 parent
867fd42972
commit
9f0601027c
400 files changed
+26401
-3
No files matched your search
@@ -0,0 +1,72 @@
|
||||
/* ── how much of this the phone may hold ────────────────────────────────
|
||||
The desktop bounds the identical map with these two numbers
|
||||
(src/lib/state.svelte.js: ART_THUMB_CACHE_MAX, ART_THUMB_CACHE_MAX_CHARS,
|
||||
trimmed in insertion order by trimResolvedCache). Kept exactly as they
|
||||
are rather than invented here: `album_art` answers with base64 JPEG of a
|
||||
360px thumbnail on both, so 512 covers is the same budget either side.
|
||||
Until now nothing on the phone gave a byte of it back — one browse of a
|
||||
114-cover library retains every one of them for the WebView's lifetime,
|
||||
and a catalog crawl adds to the same map without limit. */
|
||||
const ART_MAX = 512;
|
||||
const ART_MAX_CHARS = 16 * 1024 * 1024;
|
||||
|
||||
/* The desktop may drop any cold entry, because every caller there asks
|
||||
through getArt(path). The phone's templates INDEX this map — art[path] in
|
||||
Cover, Release, Sheet, Viewer, Artist, Discography, Home and the media
|
||||
card — so a key something is painting would blank on the spot, and
|
||||
Cover's `visible` action re-arms only when its path PROP changes, so an
|
||||
evicted cover that is still mounted would never come back at all. Hence
|
||||
two rules the desktop does not need: never the entry that has just
|
||||
landed, and never one that a connected <img> is showing. Oldest first
|
||||
otherwise — Object.keys is insertion order here, because every key is a
|
||||
file path, an https URL or a "stream:" string and never integer-like,
|
||||
which would be hoisted to the front and go first. A remembered failure
|
||||
("" so it is not retried) is evictable like anything else: past the cap
|
||||
a retry is the cheaper of the two.
|
||||
|
||||
The map is allowed to sit OVER its cap for as long as one screen needs
|
||||
all of it — a mounted grid of 600 covers loses none of them — and it
|
||||
comes down the moment that screen goes.
|
||||
|
||||
Called from pump() and nowhere else, which is never inside an $effect:
|
||||
Object.keys on a $state proxy reads the version signal, so an effect
|
||||
that called this would re-run on every cover that lands. The two
|
||||
writers that do not go through pump() — loadArt's data: short-circuit
|
||||
and a stream's tag art in player.svelte.js — are therefore bounded at
|
||||
the next cover that does, which on any screen worth the name is the
|
||||
next one. Under the cap
|
||||
it is a key count and a char sum and returns; the pass over the screen's
|
||||
images is built once, lazily, and only when there is something to drop,
|
||||
because reading a base64 src is a copy of the whole data URL. */
|
||||
function trimArt(justAdded) {
|
||||
const keys = Object.keys(art);
|
||||
let chars = 0;
|
||||
for (const k of keys) { const v = art[k]; if (typeof v === "string") chars += v.length; }
|
||||
let live = keys.length;
|
||||
if (live <= ART_MAX && chars <= ART_MAX_CHARS) return;
|
||||
let painted = null;
|
||||
for (const k of keys) {
|
||||
if (live <= ART_MAX && chars <= ART_MAX_CHARS) break;
|
||||
if (k === justAdded) continue;
|
||||
const v = art[k];
|
||||
if (v) {
|
||||
if (!painted) {
|
||||
painted = new Set();
|
||||
/* the attribute, not the .src property: for a data URL they
|
||||
are the same string and the property re-serializes it.
|
||||
The fallback is for an <img> whose src was set as a
|
||||
property instead — none today, and a miss here is the one
|
||||
way this could blank a cover. */
|
||||
for (const img of document.images) {
|
||||
if (!img.isConnected) continue;
|
||||
const src = img.getAttribute("src") || img.src;
|
||||
if (src) painted.add(src);
|
||||
}
|
||||
}
|
||||
if (painted.has(v)) continue;
|
||||
}
|
||||
delete art[k];
|
||||
if (typeof v === "string") chars -= v.length;
|
||||
live--;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user