Problem — ImageGen.jsx threads statusLoading into disabled on 14 controls, including the prompt textarea, the negative-prompt textarea, the universe picker and the style-preset picker — all of which are pure client-side form state that has nothing to do with whether a Stable Diffusion backend answered. statusLoading is set true on mount and again on every backend-chip / model change, and the code's own comment says the probe can take a long time ("the initial external probe timing out against an unconfigured SD API URL"). The result: the user lands on /media/image, the form that fills the entire above-the-fold region is greyed out and unresponsive, and it goes dead again every time they switch backends. The sibling page VideoGen.jsx — same shell, same probe — gates exactly one control (the refresh button), which is the correct behaviour and the model to copy.
Evidence — client/src/pages/ImageGen.jsx:286:
const refreshStatus = useCallback((mode, localModelId) => {
const myToken = ++statusRequestToken.current;
setStatusLoading(true);
getImageGenStatus(mode, mode === IMAGE_GEN_MODE.LOCAL ? localModelId : undefined)
and the form, client/src/pages/ImageGen.jsx:1291-1320:
<UniverseStylePicker value={selectedUniverse?.id || ''} onChange={setSelectedUniverse} disabled={statusLoading} />
<StylePresetPicker value={stylePreset?.id || ''} onChange={setStylePreset} disabled={statusLoading} />
…
<AutoSizeTextarea value={prompt} onChange={(e) => setPrompt(e.target.value)} rows={3}
disabled={statusLoading}
… placeholder="Describe the image you want to generate..." />
grep -c 'disabled={statusLoading}' client/src/pages/ImageGen.jsx → 14. The same grep on client/src/pages/VideoGen.jsx → 1 (:841, the Refresh status button).
Plan
- In
client/src/pages/ImageGen.jsx, introduce const probeGated = statusLoading; and keep it ONLY on the controls whose behaviour genuinely depends on the probe result: the Refresh-status button (:1274), the BackendChipStrip (:1265), and the Generate submit button. Decision: the probe determines which backend can run, not what the user can type, so only backend-selection and submit are gated — this matches VideoGen and removes the dead-form window entirely.
- Remove
disabled={statusLoading} from the remaining controls: UniverseStylePicker (:1291), StylePresetPicker (:1296), both AutoSizeTextarea prompt fields (:1309, :1319), PromptEnhancer (:1333), PromptFromMedia (:1340), and the parameter inputs at :1352, :1379, :1400, :1434, :1448, :1463.
- Keep the Generate button disabled while
statusLoading is true so the user cannot submit against an unknown backend, and give it the existing "Checking…" label so the reason is visible rather than a mystery grey button.
- Leave the status pill's
statusLoading ? … 'Checking {effectiveMode}…' branch at :1235 as-is — it is the correct progressive-disclosure affordance.
Tests
- Extend
client/src/pages/ImageGen.test.jsx with a test that renders with getImageGenStatus pending and asserts the prompt textarea is NOT disabled while the Generate button IS. Uniquely catches a regression that re-couples form input to the probe.
- Add a second case asserting that after the probe resolves with
connected: false, Generate stays disabled and the prompt textarea stays enabled.
Acceptance criteria
grep -c 'disabled={statusLoading}' client/src/pages/ImageGen.jsx is at most 3.
- On a cold load of
/media/image the user can type a prompt before the status pill resolves.
- Switching backend chips no longer blanks out the form.
Out of scope — the status-probe implementation, backend-readiness gating logic in imageGenReadiness, and VideoGen's own gating.
Filed by a /do:better --scan-only --issues audit (2026-09-01). Category: ux · Severity: high · Files: client/src/pages/ImageGen.jsx:286, client/src/pages/ImageGen.jsx:1309, client/src/pages/ImageGen.jsx:1319, client/src/pages/ImageGen.jsx:1291, client/src/pages/VideoGen.jsx:841
All labels already exist in the repo; do NOT create labels. Never add planner:* labels.
Problem —
ImageGen.jsxthreadsstatusLoadingintodisabledon 14 controls, including the prompt textarea, the negative-prompt textarea, the universe picker and the style-preset picker — all of which are pure client-side form state that has nothing to do with whether a Stable Diffusion backend answered.statusLoadingis set true on mount and again on every backend-chip / model change, and the code's own comment says the probe can take a long time ("the initialexternalprobe timing out against an unconfigured SD API URL"). The result: the user lands on/media/image, the form that fills the entire above-the-fold region is greyed out and unresponsive, and it goes dead again every time they switch backends. The sibling pageVideoGen.jsx— same shell, same probe — gates exactly one control (the refresh button), which is the correct behaviour and the model to copy.Evidence —
client/src/pages/ImageGen.jsx:286:and the form,
client/src/pages/ImageGen.jsx:1291-1320:grep -c 'disabled={statusLoading}' client/src/pages/ImageGen.jsx→ 14. The same grep onclient/src/pages/VideoGen.jsx→ 1 (:841, the Refresh status button).Plan
client/src/pages/ImageGen.jsx, introduceconst probeGated = statusLoading;and keep it ONLY on the controls whose behaviour genuinely depends on the probe result: the Refresh-status button (:1274), theBackendChipStrip(:1265), and the Generate submit button. Decision: the probe determines which backend can run, not what the user can type, so only backend-selection and submit are gated — this matches VideoGen and removes the dead-form window entirely.disabled={statusLoading}from the remaining controls:UniverseStylePicker(:1291),StylePresetPicker(:1296), bothAutoSizeTextareaprompt fields (:1309, :1319),PromptEnhancer(:1333),PromptFromMedia(:1340), and the parameter inputs at :1352, :1379, :1400, :1434, :1448, :1463.statusLoadingis true so the user cannot submit against an unknown backend, and give it the existing "Checking…" label so the reason is visible rather than a mystery grey button.statusLoading ? … 'Checking {effectiveMode}…'branch at :1235 as-is — it is the correct progressive-disclosure affordance.Tests
client/src/pages/ImageGen.test.jsxwith a test that renders withgetImageGenStatuspending and asserts the prompt textarea is NOT disabled while the Generate button IS. Uniquely catches a regression that re-couples form input to the probe.connected: false, Generate stays disabled and the prompt textarea stays enabled.Acceptance criteria
grep -c 'disabled={statusLoading}' client/src/pages/ImageGen.jsxis at most 3./media/imagethe user can type a prompt before the status pill resolves.Out of scope — the status-probe implementation, backend-readiness gating logic in
imageGenReadiness, and VideoGen's own gating.Filed by a
/do:better --scan-only --issuesaudit (2026-09-01). Category:ux· Severity:high· Files:client/src/pages/ImageGen.jsx:286, client/src/pages/ImageGen.jsx:1309, client/src/pages/ImageGen.jsx:1319, client/src/pages/ImageGen.jsx:1291, client/src/pages/VideoGen.jsx:841All labels already exist in the repo; do NOT create labels. Never add
planner:*labels.