The field was rendered in every non-managed user's own Map settings and written
to their personal settings row. The CSP is built from something else: bootstrap
reads the ADMIN default and puts that origin into `connect-src`. So filling the
field in was the one path the product offered, and it could not work — the route
calculator happily built its URLs against the typed origin and the browser
refused every one of them with a bare TypeError, not a status, so no fallback and
no retry could see it. Day-plan routes, transport legs, the mobile day route,
Studio's road route and the whole road-trip rail stopped routing, app-wide, with
a generic "route could not be calculated". Nothing in the UI could repair it
except emptying the field again, and there was no admin field to set the value
that would have made the origin allowed.
The repo has decided this shape once already: `llm_base_url` is admin-only
because it names where the server sends its own requests and only whoever runs
the instance can judge what is reachable. This is the same class for a different
reason, so it joins the same guard, which is now named for what it actually
covers. Clearing stays open to everyone, so a row written before the rule cleans
itself up rather than blocking the save.
The field moves to the admin's default-user settings, next to the tile URL and
the Carto key, where a value takes effect.
An assistant rendering a temperature, a distance or a clock time was
guessing: the session instructions named only the trip currency, and nothing
could read what the user had picked.
The write works off an allow-list rather than off the settings row, because
that row also holds the webhook URL, the ntfy token and the Mapbox, Carto
and LLM keys, and getUserSettings hands some of those back in cleartext.
Everything outside the list is refused, including a key nobody has heard of
yet. The guard test asserts against the service's own encrypted and masked
sets rather than a copy of them, so a sixth key added there fails it.