[1.57.2] — 2026-05-19
fix(config): the ACTUAL root cause of /#/config "validation failed" — the SPA-injected lang field.
🐛 Fixes
- Saving anything on
/#/configfrom the browser always returnedvalidation failed.public/js/api.jsauto-attaches alangfield to every JSON POST body (so LLM routes pick up the UI locale)./api/configis not an LLM route andlangis not a config key, sovalidateConfig's (correct, security-relevant) unknown-key rejection 400'd every Save withvalidation failed — lang: not a known config key. This was browser-only: curl/in-process repros never sentlang, which is why v1.57.0/.1 (whitespace-trim, descriptive errors) improved the message but didn't fix the cause. The config route now strips the transport-onlylangbefore validating; theKNOWN_KEYSwrite-filter still drops any genuinely-unknown key, so the attacker-injection guard is unchanged. - Found by a new Playwright form sweep that drives the real save button — not the synthetic fetch repros that masked it.
🧪 Tests
- New
tests/playwright-forms.mjs(26, wired intonpm run test:e2e:browser): drives a real Chromium over every form-bearing route — asserts no console errors site-wide, the invalid-save toast shows field+reason+request-context, secret fields never echo the typed value, valid saves succeed, and PORT/HOST show their prefilled defaults. tests/config-endpoint.test.mjs: browser-parity cases — POST withlangsucceeds (andlangnever lands in.env), while a real unknown key withlangpresent is still rejected. 879 → 881 unit; Playwright 32 → 58.