Problem
Settings > Security collapses “authentication status could not be loaded” into “authentication is disabled.” SecurityTab initializes enabled to false at client/src/components/settings/SecurityTab.jsx:15, suppresses every getAuthStatus rejection at client/src/components/settings/SecurityTab.jsx:24, and still clears the loading state at client/src/components/settings/SecurityTab.jsx:28. The settled UI then renders Login password disabled at client/src/components/settings/SecurityTab.jsx:93 and selects the first-time Set a password / Enable login branch at client/src/components/settings/SecurityTab.jsx:112 and client/src/components/settings/SecurityTab.jsx:148.
That is not a valid fallback for this endpoint. /api/auth/status is the authoritative public status read (client/src/services/apiAuth.js:5, server/routes/auth.js:37); a rejected or malformed response says nothing about whether auth is enabled.
Trigger
- Open
/settings/security.
- Have
GET /api/auth/status reject because the server is temporarily unreachable or its settings read fails.
- The request is silent and the component's catch returns
null, so the spinner disappears and the page reports that the login password is disabled.
- If auth is actually enabled, the page also omits the current-password field and presents the wrong mutation flow; the later password request can only fail after the user has acted on the false status.
Impact
The security screen gives a definitive, incorrect answer about whether the instance is password-gated. Users can make access-control decisions from stale fiction and are led into a form that cannot succeed for the actual server state.
Fix
- In
client/src/components/settings/SecurityTab.jsx, represent status as an explicit sentinel (null = not loaded) plus a load error; do not initialize a real disabled state before a validated response arrives.
- Accept only a response containing a boolean
enabled. Treat a rejected or malformed response as an error rather than coercing it with !!s?.enabled.
- While status is unknown, render neither the enabled nor disabled password forms. Show an inline error with a Retry button that re-runs the status request and restores the appropriate form only after a valid response.
- Add
client/src/components/settings/SecurityTab.test.jsx covering enabled and disabled success responses, rejection, malformed success payload, and successful retry.
Rejected alternative: toast the load error and continue rendering the disabled branch. A transient toast does not repair the false persistent state, and the wrong mutation form would remain actionable.
Dispatch rationale: model:light fits a localized state/render correction; effort:medium is warranted because the unknown/error/success states and retry behavior must remain mutually exclusive.
Acceptance criteria
Problem
Settings > Security collapses “authentication status could not be loaded” into “authentication is disabled.”
SecurityTabinitializesenabledtofalseatclient/src/components/settings/SecurityTab.jsx:15, suppresses everygetAuthStatusrejection atclient/src/components/settings/SecurityTab.jsx:24, and still clears the loading state atclient/src/components/settings/SecurityTab.jsx:28. The settled UI then rendersLogin password disabledatclient/src/components/settings/SecurityTab.jsx:93and selects the first-timeSet a password/Enable loginbranch atclient/src/components/settings/SecurityTab.jsx:112andclient/src/components/settings/SecurityTab.jsx:148.That is not a valid fallback for this endpoint.
/api/auth/statusis the authoritative public status read (client/src/services/apiAuth.js:5,server/routes/auth.js:37); a rejected or malformed response says nothing about whether auth is enabled.Trigger
/settings/security.GET /api/auth/statusreject because the server is temporarily unreachable or its settings read fails.null, so the spinner disappears and the page reports that the login password is disabled.Impact
The security screen gives a definitive, incorrect answer about whether the instance is password-gated. Users can make access-control decisions from stale fiction and are led into a form that cannot succeed for the actual server state.
Fix
client/src/components/settings/SecurityTab.jsx, represent status as an explicit sentinel (null= not loaded) plus a load error; do not initialize a real disabled state before a validated response arrives.enabled. Treat a rejected or malformed response as an error rather than coercing it with!!s?.enabled.client/src/components/settings/SecurityTab.test.jsxcovering enabled and disabled success responses, rejection, malformed success payload, and successful retry.Rejected alternative: toast the load error and continue rendering the disabled branch. A transient toast does not repair the false persistent state, and the wrong mutation form would remain actionable.
Dispatch rationale:
model:lightfits a localized state/render correction;effort:mediumis warranted because the unknown/error/success states and retry behavior must remain mutually exclusive.Acceptance criteria
enabled: false.