Filed unassigned by the domain:ui execution seat as an out-of-scope finding while implementing objectui#6658 (the callable guard on the same file). Not fixed there — that PR is scoped to the save-door guard and touches only the save path plus a new pin file.
What ESLint reports today
packages/react/src/hooks/useSchemaPersistence.ts carries three react-hooks/refs warnings, all on lines this seat did not touch (they pre-date objectui#6658's branch — the diff there is three pure insertions, and the warned lines are byte-identical to origin/main).
Measured on faac0d935, pnpm exec eslint packages/react --format json: 131 files linted, 0 errors, 380 warnings package-wide, of which this file holds 3:
useSchemaPersistence.ts:211 react-hooks/refs Cannot access ref value during render
useSchemaPersistence.ts:213 react-hooks/refs Cannot update ref during render
useSchemaPersistence.ts:213 react-hooks/refs Cannot access ref value during render
The shape:
const defaultAdapter = useRef(createLocalStorageAdapter());
const adapterRef = useRef(adapter ?? defaultAdapter.current);
// Keep the ref up to date if the adapter prop changes
adapterRef.current = adapter ?? defaultAdapter.current;
Both reading defaultAdapter.current and assigning adapterRef.current happen in the render body.
Why it may matter
React's own rule flags this because a ref written during render is not safe under concurrent rendering: a render that React discards or replays still performed the write. Here the written value is the persistence adapter, so the observable risk is a save routed through an adapter from a render that never committed.
This is a warning, not an error, and pnpm lint is green (0 errors package-wide), so nothing is red today. No user-visible break has been measured — filing as an observation for triage rather than asserting impact.
Reproduce
pnpm exec eslint packages/react/src/hooks/useSchemaPersistence.ts --format json
Dedupe search run before filing: the repo-scoped /search/issues REST endpoint answers 403 for this seat, so this went through the REST list endpoint plus a local grep — 239 open issues collected, zero hits for useSchemaPersistence, react-hooks/refs or "ref during render"; control words hit in the same read (36 titles match "schema", and objectui#6658 itself is present), so the empty result is a real reading rather than a broken one.
Generated by Claude Code
Filed unassigned by the
domain:uiexecution seat as an out-of-scope finding while implementing objectui#6658 (the callable guard on the same file). Not fixed there — that PR is scoped to the save-door guard and touches only thesavepath plus a new pin file.What ESLint reports today
packages/react/src/hooks/useSchemaPersistence.tscarries threereact-hooks/refswarnings, all on lines this seat did not touch (they pre-date objectui#6658's branch — the diff there is three pure insertions, and the warned lines are byte-identical toorigin/main).Measured on
faac0d935,pnpm exec eslint packages/react --format json: 131 files linted, 0 errors, 380 warnings package-wide, of which this file holds 3:The shape:
Both reading
defaultAdapter.currentand assigningadapterRef.currenthappen in the render body.Why it may matter
React's own rule flags this because a ref written during render is not safe under concurrent rendering: a render that React discards or replays still performed the write. Here the written value is the persistence adapter, so the observable risk is a save routed through an adapter from a render that never committed.
This is a warning, not an error, and
pnpm lintis green (0 errors package-wide), so nothing is red today. No user-visible break has been measured — filing as an observation for triage rather than asserting impact.Reproduce
Dedupe search run before filing: the repo-scoped
/search/issuesREST endpoint answers 403 for this seat, so this went through the REST list endpoint plus a local grep — 239 open issues collected, zero hits foruseSchemaPersistence,react-hooks/refsor "ref during render"; control words hit in the same read (36 titles match "schema", and objectui#6658 itself is present), so the empty result is a real reading rather than a broken one.Generated by Claude Code