fix(site): resolve WS/HTTP race condition on workspace parameters page (#22556)

## Problem

Flaky e2e test: `update workspace, new required, mutable parameter
added`

```
Error: Timed out 15000ms waiting for expect(locator).toHaveValue(expected)
Locator: getByTestId('parameter-field-Sixth parameter').locator('input')
Expected string: "99"
Received string: ""
```

## Root Cause

When the workspace parameters page loads, the WebSocket sends an initial
response with template defaults. For parameters with no default (like
`sixth_parameter`), the server returns `{valid: false, value: ""}`. On
first render, `useSyncFormParameters` sees this invalid server value and
overwrites the form's correctly-autofilled value ("99" from the previous
build) with "".

## Fix

When the server value is `{valid: false}`, preserve the current form
value instead of overwriting with "". This prevents the sync hook from
clobbering autofilled values before the server has had a chance to
process them.

## Verification

- TypeScript: zero type errors
- Biome lint: clean
- Unit tests: 2/2 passing
- **E2E soak test: 849/854 passed across 854 runs (99.5% pass rate)**
  - 0 occurrences of the original flake (empty value on settings page)
- 5 residual failures are a separate pre-existing race in
`fillParameters` where user input is overwritten during the 500ms
debounce window
This commit is contained in:
Kyle Carberry
2026-03-04 16:20:49 +00:00
committed by GitHub
parent 619023f5fc
commit 17d214b4a4
@@ -27,16 +27,30 @@ export function useSyncFormParameters({
useEffect(() => {
if (!parameters) return;
const currentFormValues = formValuesRef.current;
const newParameterValues = parameters.map((param) => ({
name: param.name,
value: param.value.valid ? param.value.value : "",
}));
const currentFormValuesMap = new Map(
currentFormValues.map((value) => [value.name, value.value]),
);
const newParameterValues = parameters.map((param) => {
// When the server value is not valid (e.g., the initial
// WebSocket response before any user input is sent),
// preserve the current form value. This prevents the sync
// hook from overwriting autofilled values (from the
// previous build) with empty strings before the server
// has had a chance to process them.
if (!param.value.valid) {
const existingValue = currentFormValuesMap.get(param.name);
if (existingValue !== undefined) {
return { name: param.name, value: existingValue };
}
}
return {
name: param.name,
value: param.value.valid ? param.value.value : "",
};
});
const isChanged =
currentFormValues.length !== newParameterValues.length ||
newParameterValues.some(