Files
SoulStream/handoff/rounds/ins-r26-diag.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

109 lines
5.7 KiB
Plaintext

<script>
/* Diagnostics — the desktop's debug overlay (Ctrl+Shift+D) as a screen,
on the dev flavour only: what this process costs the phone, what the
network is moving, the track playing and its loudness correction, the
tracks the pre-buffer is fetching behind it, and how big the play
history has grown. Polled once a second while the screen is open and
never otherwise, the way the overlay does it. The GPU counters are
Windows PDH and the private commit is a Win32 call, so neither row is
here — on the phone they would read nothing at all. */
import Icon from "../../components/Icon.svelte";
import * as api from "../../lib/api.js";
import { fmtBytes, basename } from "../util.js";
let stats = $state(null);
let plays = $state(null);
let failed = $state("");
/* nothing reactive is READ in here: the effect runs once when the screen
mounts and its cleanup when the screen leaves. An effect that reads
what it writes takes its whole subtree down with it. */
$effect(() => {
let live = true;
const tick = async () => {
try {
const s = await api.debugStats();
if (live) { stats = s; failed = ""; }
} catch (e) {
if (live) failed = String(e);
}
};
void tick();
api.playRowCount().then((n) => { if (live) plays = n; }, () => {});
const id = setInterval(tick, 1000);
return () => { live = false; clearInterval(id); };
});
const pct = (v) => (v == null ? "—" : v.toFixed(1) + "%");
const size = (n) => (n ? fmtBytes(n) : "—");
const rate = (n) => (n ? fmtBytes(n) + "/s" : "—");
const db = (v) => (v == null ? "—" : (v > 0 ? "+" : "") + v.toFixed(1) + " dB");
const upfor = (s) => {
if (s == null) return "—";
const h = Math.floor(s / 3600), m = Math.floor((s % 3600) / 60);
return h ? h + " hr " + m + " min" : m ? m + " min" : s + " s";
};
const share = (p) => (p.total ? Math.max(0.02, Math.min(1, p.received / p.total)) : 0);
</script>
<div class="phead"><div class="row"><h1>Diagnostics</h1></div></div>
<div class="sec-note">The desktop's debug overlay, on the dev flavour. Polled once a second while this screen is open.</div>
{#if failed}
<div class="stub">
<b>No diagnostics.</b>
{failed}
</div>
{/if}
<div class="sheet-sec">This process</div>
<div class="group diag">
<div class="kv"><span class="k">App CPU</span><span class="v">{pct(stats?.cpuProcess)}</span></div>
<div class="kv"><span class="k">System CPU</span><span class="v">{pct(stats?.cpuSystem)}</span></div>
<div class="kv"><span class="k">Memory</span><span class="v">{size(stats?.memWorkingSet)}</span></div>
<div class="kv"><span class="k">System memory</span><span class="v dim">{size(stats?.memSystemUsed)} of {size(stats?.memSystemTotal)}</span></div>
<div class="kv"><span class="k">Processes</span><span class="v">{stats?.processCount ?? "—"}</span></div>
<div class="kv"><span class="k">Up</span><span class="v">{upfor(stats?.uptimeSecs)}</span></div>
</div>
<div class="sec-note">Processes counts this app's own tree. Android runs the WebView in a system process of its own, so it is outside these numbers; on the desktop the whole WebView2 family is inside them.</div>
<div class="sheet-sec">Network</div>
<div class="group diag">
<div class="kv"><span class="k">Down</span><span class="v">{rate(stats?.netRxBps)}</span></div>
<div class="kv"><span class="k">Up</span><span class="v">{rate(stats?.netTxBps)}</span></div>
</div>
<div class="sec-note">Every interface on the phone, not this app alone.</div>
<div class="sheet-sec">The track playing</div>
<div class="group diag">
<div class="kv"><span class="k">Stream</span><span class="v">{!stats ? "—" : stats.dlTotal ? size(stats.dlReceived) + " of " + size(stats.dlTotal) + (stats.dlDone ? " · done" : "") : "nothing streaming"}</span></div>
<div class="kv"><span class="k">Normalization</span><span class="v">{!stats ? "—" : stats.normalizationEnabled ? "on · " + (stats.targetLufs ?? -14) + " LUFS" : "off"}</span></div>
<div class="kv"><span class="k">Measured</span><span class="v dim">{stats?.loudness?.lufs != null ? stats.loudness.lufs.toFixed(1) + " LUFS" + (stats.loudness.analyzing ? " · measuring" : "") : "—"}</span></div>
<div class="kv"><span class="k">Gain</span><span class="v">{db(stats?.normNowDb)}{stats && stats.normNowDb != null && stats.normNowDb !== stats.normTargetDb ? " → " + db(stats.normTargetDb) : ""}</span></div>
</div>
<div class="sheet-sec">On deck</div>
{#if stats?.preloadDl?.length}
<div class="group diag-deck">
{#each stats.preloadDl as p (p.username + p.path)}
<div class="row">
<span class="lead"><Icon name="download" size={20} /></span>
<span class="b">
<span class="t">{basename(p.path)}</span>
<span class="m">{p.username} · {p.state}{p.place != null ? " · queue " + p.place : ""}{p.speedBps ? " · " + fmtBytes(p.speedBps) + "/s" : ""}</span>
{#if p.total}<span class="lbar"><i style="transform: scaleX({share(p).toFixed(3)})"></i><em>{fmtBytes(p.received)}</em></span>{/if}
</span>
</div>
{/each}
</div>
{:else}
<div class="sec-note">Nothing pre-buffering. The player readies the next three tracks while one plays.</div>
{/if}
<div class="sheet-sec">Library</div>
<div class="group diag">
<div class="kv"><span class="k">Play rows</span><span class="v">{plays != null ? plays.toLocaleString() : "—"}</span></div>
</div>
<div class="endpad"></div>