The first pass at this covered the two admin cards. It missed the pickers that
matter most: the per-tab model selectors in app.js, which every clinical tab
uses, and the My Resources model dropdown. Both were filled once at page load,
so a model added in Admin was still invisible where people actually choose one.
app.js's boot fetch is now a named loadModelList() that also runs on
models-changed; My Resources re-runs loadOptions(), which is the same call that
decides whether the model row is shown at all.
Both rebuilds keep a choice already made. These selects can be rebuilt while
someone is halfway through a form, and silently moving them off the model they
picked would be worse than not refreshing.
Verified against a mutation: removing the app.js listener fails the test that
says every picker listens.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dv6sqaY6Vq3ChZHMem3cnU
Adding a discovered model refreshed exactly one dropdown — the default-model
one, in the same card. Every other picker had been filled when the admin tab
loaded, behind a guard that makes its loader run once per visit, so the
Clinical Assistant chat model, the allowed-models list, the slide reviewer and
the image-model selects all kept the roster they were given. The model was
genuinely added; it simply could not be selected until the page was reloaded,
which reads as the add having failed.
Every mutation of the roster — add, remove, clear-all, enable/disable — now
dispatches `models-changed`, and the cards that list models listen and refetch.
The event carries no payload: a listener re-reads the list itself, so there is
one source of truth rather than a copy to keep in step. Same pattern as the
existing `assistant-image-roster` event.
Each listener clears its own guard before re-running, and returns early if a
load is already in flight. The assistant loader keeps unsaved drafts, so
re-running it costs nothing but a refreshed set of options.
The add toast said "now select it as default and click Set Default" — advice
that only made sense when the default dropdown was the one thing that updated.
Verified against a mutation: removing the guard reset fails the propagation
test, because the listener then fires into a loader that returns early.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dv6sqaY6Vq3ChZHMem3cnU