Prevent terminal hydration drift and improve settings semantics - #1237
Prevent terminal hydration drift and improve settings semantics#1237open-inspect[bot] wants to merge 1 commit into
Conversation
Terraform Validation Results
Pushed by: @open-inspect[bot], Action: |
| {mode === "create" ? ( | ||
| <div> | ||
| <label className="block text-sm font-medium text-foreground mb-1.5">Trigger Type</label> | ||
| <div className="block text-sm font-medium text-foreground mb-1.5">Trigger Type</div> |
There was a problem hiding this comment.
[deep review] This removes the invalid standalone label, but it leaves the mutually exclusive choices semantically unnamed and ungrouped: TriggerTypeSelector still renders plain buttons with no selected-state semantics. Please make this a real field boundary (fieldset/legend with native radios, or a named radiogroup with aria-checked) so the structure expresses the model instead of only changing the heading element.
| htmlFor="automation-repository-configuration" | ||
| className="block text-sm font-medium text-foreground mb-1.5" | ||
| > | ||
| Repository Configuration |
There was a problem hiding this comment.
[deep review] The new htmlFor association does not become the button’s accessible name because the existing aria-label="Repository selection" takes precedence. That makes this added label/id wiring competing, ineffective semantics. Please keep one canonical naming path, ideally by removing the redundant aria-label and letting the visible associated label name the trigger (or using aria-labelledby if both visible strings are intentionally part of the name).
| const uploadedByIdRef = useRef( | ||
| new Map<string, { sessionId: string; attachment: SessionAttachmentReference }>() | ||
| ); | ||
| const uploadedByIdRef = useRef<Map< |
There was a problem hiding this comment.
[deep review] This behavior-neutral rewrite adds nullable state, render-time mutation, an alias, and callback dependencies merely to hold a stable Map; the same protocol is then repeated for sets in use-session-participant-profiles and use-session-socket. That moves complexity around without deleting any. Please restore the direct initialized refs and use .current inside callbacks/effects. If lazy mutable-ref initialization is genuinely a project requirement, give it one canonical hook rather than copy-pasting this ceremony across unrelated hooks.
Prevents persisted terminal state from producing a server/client hydration mismatch and gives grouped settings controls accurate accessible structure.
Root-cause tasks
Fixed 10 root-cause tasks:
react-doctor/no-hydration-branch-on-browser-global-packages/web/src/app/(app)/session/[id]/page.tsx- terminal visibility readlocalStorageduring initial render. The preference now usesuseSyncExternalStorewith a stable server snapshot, preventing hydration drift and inconsistent terminal rendering. Human severity: high.react-doctor/rerender-lazy-ref-init-packages/web/src/hooks/use-session-attachments.ts- an upload cacheMapwas allocated on every render and discarded after the first. Lazy initialization avoids unnecessary allocations in the attachment composer. Human severity: low.react-doctor/rerender-lazy-ref-init-packages/web/src/hooks/use-session-participant-profiles.ts- the attempted-profile IDSetwas reallocated on every render. Lazy initialization reduces avoidable work during participant updates. Human severity: low.react-doctor/rerender-lazy-ref-init-packages/web/src/hooks/use-session-socket.ts- the subscription waiterSetwas reallocated on every socket-hook render. Lazy initialization avoids churn on a high-activity session path. Human severity: low.react-doctor/label-has-associated-control-packages/web/src/components/automations/automation-form.tsx- the trigger-type group heading was an unassociated form label. It is now neutral text, avoiding misleading label semantics for assistive technology. Human severity: medium.react-doctor/label-has-associated-control-packages/web/src/components/automations/automation-form.tsx- the repository configuration label did not identify its popover trigger. MatchinghtmlFor/idvalues now associate the visible label with the control. Human severity: medium.react-doctor/label-has-associated-control-packages/web/src/components/settings/sandbox-settings.tsx- Service Ports was an unassociated label for two controls. Afieldset/legendnow exposes the controls as one named group. Human severity: medium.react-doctor/label-has-associated-control-packages/web/src/components/settings/sandbox-settings.tsx- Tunnel Ports was an unassociated label for a dynamic control group. Afieldset/legendnow provides group semantics without changing the visible heading. Human severity: medium.react-doctor/label-has-associated-control-packages/web/src/components/settings/sandbox-settings.tsx- Child Sessions was an unassociated label for two limits. Afieldset/legendnow gives screen-reader users the shared context. Human severity: medium.react-doctor/label-has-associated-control-packages/web/src/components/settings/sandbox-settings.tsx- Resources was an unassociated label for CPU and memory controls. Afieldset/legendnow names that control group. Human severity: medium.All selected diagnostics were ungrouped. No non-null
fixGroupIdwas selected or split. Diagnostics with a sharedfixGroupIdremain deferred as complete groups.React Doctor results
no-hydration-branch-on-browser-global: 1 → 0rerender-lazy-ref-init: 3 → 0label-has-associated-control: 13 → 7Validation
npm run typecheck -w @open-inspect/webafter the error fix and after each warning task: passednpm run typecheck -w @open-inspect/web: passednpm run lint -w @open-inspect/web: passednpx prettier --check packages/web: passednpm test -w @open-inspect/web: passed, 111 files and 852 testsorigin/main: no new finding; it reports the pre-existingprefer-useReducerwarning atsandbox-settings.tsx:234npm run build -w @open-inspect/web: still fails at the same pre-existing/automations/newprerender withCannot read properties of null (reading 'useContext'), digest2120487162; compilation and TypeScript complete successfully before that failureExisting failures
.opencode/package.json; the web-only formatting check passes.effect-needs-cleanuperror is a validated false positive: the effect calls a callback that creates the WebSocket, and the effect's returned teardown closes that same socket, matching the canonical rule exclusion.Deferred
no-giant-component) and reducer migrations remain for later code-owner-reviewed batches.fixGroupIdwas split.Visual verification
Browser visual verification was not run. The UI edits are intended to be visually neutral semantic changes, and the terminal change affects hydration/state synchronization rather than layout; lint, typecheck, and focused interaction tests cover the touched behavior.
Created with Open-Inspect