Files
sencho/backend
Anso bcc4b7e00a fix(frontend): stop client-side preference changes refetching all settings (#2008)
* fix(frontend): stop client-side preference changes refetching all settings

The Playwright suite was failing intermittently with HTTP 429 from the global
API limiter. Instrumenting a real run showed why: 22,177 API requests over 19.6
minutes, 58% of them 304 Not Modified, and the shared admin bucket averaging
about 970 requests/min against its 1000 ceiling, so ordinary bursts were
rejected. The failures surfaced far from the burst, as the stacks view failing
to load and the Create Stack button never appearing, which reads like an
unrelated UI fault rather than a rate-limit problem.

GET /api/settings was a quarter of all traffic, peaking at 461/min with 3,810 of
4,781 responses being 304s. useDeveloperMode treated a settings-changed event
with no changedKeys as "refetch", and fourteen dispatch sites across ten hooks
broadcast with no detail at all. Every one of them is a client-side preference
backed by localStorage: pane layout (four sites), density, top-nav alignment,
mode and labels, log chip colours, deploy feedback, quick links. So dragging a
panel divider or nudging the top nav pulled the whole server-side settings
document over the network for a change with no server-side effect.

useDeveloperMode now refetches only when changedKeys names developer_mode,
matching the two listeners that already gate this way. All three server-side
write sites dispatch changedKeys, so a real developer_mode toggle still
propagates immediately.

The non-production ceiling of the global limiter moves to 10000 so the suite,
which shares one account across every spec, stops tripping it. Production is
untouched at 200, still configurable with API_RATE_LIMIT. The two changes are
complements: this removes a real defect, the ceiling gives the suite headroom.

* test: rescale global rate-limit assertions to the new non-production ceiling

The pilot enrollment suite asserts which limiter applies by reading the
ratelimit-limit header, and hardcoded the global tier at 1000. That value moved,
so the assertion failed in CI. The enrollment tier's own ceiling of 100 is
unchanged, so the test still proves that a proxy-mode node creation falls back to
the global tier rather than the enrollment tier.

Two floors in the rate-limiting suite were missed in the previous commit. They
read at least 990 remaining, which against a 10000 ceiling no longer constrains
anything: the assertions passed for a reason unrelated to what they were
checking. Rescaled to 9990 so they keep their original meaning, that at most ten
requests were spent from the shared budget.

Note that these two assertions were already weak before this change: one request
per user leaves 9999 remaining when the buckets are independent and 9998 when
they are shared, so a bound of 990 admitted both. They still do. Tightening them
to 9999 would make them prove the independence their name claims, which is worth
doing separately.
2026-09-25 21:41:55 -04:00
..