Files
SoulStream/handoff/rounds/ins-r25-store.txt
T
KeelrLeek 9f0601027c 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.
2026-09-14 07:57:41 -05:00

52 lines
2.2 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/** The rows a record's own artist anchor found no count for — a feature's
* guest, a compilation's stranger — asked by each row's OWN Deezer artist
* id, the rule the desktop's search results follow. A row the backend has
* no count for keeps nothing: unknown is not a zero. */
export function loadTrackListeners(albumId, tracks) {
if (albumId == null || catalog.listeners[albumId]) return;
const want = (tracks || []).filter((t) => t.listeners == null && t.artist_id != null);
if (!want.length) return;
catalog.listeners[albumId] = { status: "loading", counts: {} };
api.catalogTrackListeners(want.map((t) => ({ artistId: t.artist_id, title: t.title }))).then(
(counts) => {
const out = {};
(counts || []).forEach((n, i) => { if (n != null && want[i]) out[want[i].id] = n; });
catalog.listeners[albumId] = { status: "ready", counts: out };
},
() => { catalog.listeners[albumId] = { status: "error", counts: {} }; },
);
}
/** Forget an artist's page and ask for it again — the desktop's
* `invalidateCatalogArtist`, for a hero that has just changed. The seed is
* kept, so the identity search does not run a second time. */
export function forgetArtist(name) {
const k = artistKey(name);
const cur = catalog.artists[k];
if (!cur) return;
delete catalog.artists[k];
lookupArtist(name, cur.seed ?? null);
}
/** A photo from this phone as an artist's hero — the desktop's Choose hero,
* through the phone's own image picker. The page is asked again, so the
* banner, the ground and the accent all follow. */
export async function heroFromPhoto(id, name) {
let r;
try { r = await api.pickImage(); } catch (e) { if (/cancelled/.test(String(e))) return false; throw e; }
if (!r?.path) return false;
const hero = await api.setArtistHero(id, r.path);
forgetArtist(name);
note(`Hero set · ${hero.width}×${hero.height}`);
return true;
}
/** The chosen hero removed — the catalog's own photos come back. */
export async function heroClear(id, name) {
const removed = await api.clearArtistHero(id);
forgetArtist(name);
note(removed ? "The catalog's own photos are back" : "No custom hero here");
}
export function lookupAlbum(id) {