Flow
How I want a key save to go
A proposal, not what the current code does.
1Try the new key
A cheap request with a short timeout.
2Pass
Swap the new key in and save the time.
3Clear refusal
Drop the new key. The old one stays.
4Timeout or service error
Hold the new key on the side and call the result unknown.
5Before sending
The menu and the send path both ask for a recent pass.
Bad keys don't stop the little chat tool from going online: it will switch into online mode with an API key it already knows is bad.
It checks the key. It writes down if the check passed. Then nothing reads that answer again.
The tool started as a local echo bot behind a password. You type, it repeats you. Then the same day's commits added a settings page to save a key for a hosted AI service, and a dropdown on the chat page that sends my message there instead. The key stays on the server. The readme says the key is checked when saved and again periodically. That's roughly true. It just doesn't stop anything. When I reread the code, I asked one thing: if the check said the opposite, what would change? One alert and one number.
Saving a bad key still saves it
When I save a key, the server tries it with a cheap request. One kind of success counts as a pass. Anything else is a fail, so a typo, a revoked key and a busy service all look the same.
Then it saves the key either way. A pass stores the time it passed. A fail stores zero. The browser shows a failure alert, but the bad key has already replaced the old one. A typo throws away a key that worked.
The dropdown only asks whether a key exists
The chat page shows the dropdown if a key is there. Sending an online message checks the same thing. If the call fails, the bot replies with a plain error. The pass time is only shown on the settings page. Nothing that sends a message looks at it.
A recheck that can only say yes
The periodic recheck runs when I log in or load the chat page. If the last pass is too old, it checks again. A pass saves a new time. A fail does nothing.
That causes three problems. A bad key makes every chat page wait on the AI service before it loads. A browser session keeps its own copy of the key, so a new key saved somewhere else doesn't reach it. And that old session can later check its old key and save it right over the new one.
The shape I want
If you're building something like this, keep three states apart: no key, a key that hasn't passed, and a key that passed recently. Hold a new key on the side and only swap it in when it passes. A clear refusal drops it. A timeout or service error is neither, so call that unknown and keep the old key. Make the dropdown and the send path both ask for a recent pass.
Remote is ready only when there's a key, it has passed, and the pass is recent enough.
Read the key from storage on each request instead of keeping a copy in the session. And treat a clear "no" from a real message as a failed check.
None of that is in these commits, and there were no tests. I got all of it from reading the code. The test I'd write first saves a junk key over a good one and checks that the good one is still there.