Line references are pinned to main at afbd7c45.
Pre-existing on main. Not introduced by #374 — both blocks are ported verbatim. Do not bisect to it. Pre-split proof below.
Where
Two sites in src/lib/settings-controller/settings-controller.ts sharing one root cause, so filed together.
// L255-269
const refreshModelStatuses = async () => {
try {
const [standard, fineTuned] = await Promise.all([
backend.settings.getModelStatus("htdemucs"),
backend.settings.getModelStatus("htdemucs_ft"),
]);
patchModels({ statuses: { ... } });
} catch {}
};
// L271-278
const refreshRuntimeStatus = async () => {
try {
stores.runtimeStatus.updateStatus(
await backend.settings.getRuntimeBootstrapStatus(),
);
syncStores();
} catch {}
};
What goes wrong
A failed status read produces nothing at all: no view state, no log, no reporter call, no rethrow. The panel keeps rendering whatever it last showed, which is either the previous values or the initial empty state.
The consequence is a settings panel that can be confidently wrong. If getModelStatus fails after a model is deleted out from under the app, the Models section keeps showing it as downloaded, at its old size and version. If getRuntimeBootstrapStatus fails, the Runtime section keeps showing a stale state — including ready for a runtime that is no longer usable. A user acting on that display (starting a separation against a model the panel says is present) hits a failure whose cause is nowhere in the UI.
The diagnosability cost is the other half. These are the two functions that answer "what does the app think is installed", and when they fail there is no signal at all — not even a console line — so a stale-panel report has nothing to go on.
Both are called from the panel-refresh paths, so this repeats on every refresh rather than being a one-shot startup condition.
Every other failure path in this file either calls notifyError or records into the matching view slice; these two are the exceptions.
Conditions
Any rejection from getModelStatus or getRuntimeBootstrapStatus — an IPC error, a backend panic surfaced as a rejected command, a filesystem error while stating the model directory, or the runtime probe failing.
Pre-existing proof
32ec36c6:src/components/Settings/SettingsOverlay.state.ts — refreshModelStatuses at L134-159 and refreshRuntimeStatus at L162-179, each ending in } catch {}.
Fix direction (my view, not the reviewer's)
The suggestion was to record the failures or add a comment explaining why they are intentionally silent. The comment option is not worth taking — there is no rationale to write down, and a comment asserting intent would make it harder to fix later.
But I would not route these to notifyError either. These refreshes run on panel open and on every subsequent refresh, so a backend that is failing steadily would produce a stream of toasts for something the user did not initiate and cannot act on from a toast.
The honest shape is to make the failure part of the view. Both slices already carry the vocabulary for it: RuntimeUpdateView has status: "checking" | "checked" | "failed" with an error field (src/lib/settings-controller/types.ts L52-55). Give the model and runtime status slices the same treatment, so the sections can render "couldn't read status" in place of stale values, with a retry. That fixes the wrong-information problem, which is the more serious half, rather than only the missing-log problem.
A reportError call alongside it is worth adding for the diagnosability half, but it should not be the whole fix — a log the user never sees does not stop the panel from lying.
Scoping note: rendering the new failure state touches the Models and Runtime sections, which are product surfaces, so docs/references/product-standards.md applies to the UI half of this change.
Not fixing here
Filed for tracking only.