From ad7575e8558af371c961e7c89f25229bfbad0dd6 Mon Sep 17 00:00:00 2001 From: Zack Jackson <25274700+ScriptedAlchemy@users.noreply.github.com> Date: Wed, 4 Nov 2026 21:01:28 -0800 Subject: [PATCH] fix(lint): main CI no longer fails on unreasoned effects Eight effects had no stated reason, so the full-repository lint on main failed and took Fork Check with it. Each now names what it syncs with. Co-Authored-By: Claude Opus 5.5 --- apps/mobile/src/components/ProjectKnowledgeFactEditor.tsx | 1 + .../web/src/components/codeExplorer/CodeExplorerDialogHost.tsx | 1 + apps/web/src/components/loom/LoomMinimap.tsx | 1 + apps/web/src/components/loom/LoomTimeline.tsx | 2 ++ apps/web/src/components/loom/LoomWeaveField.tsx | 3 ++- apps/web/src/components/loom/useLoomViewGestures.ts | 2 +- 6 files changed, 8 insertions(+), 2 deletions(-) diff --git a/apps/mobile/src/components/ProjectKnowledgeFactEditor.tsx b/apps/mobile/src/components/ProjectKnowledgeFactEditor.tsx index 42b27195758c0..facb0a3d16d35 100644 --- a/apps/mobile/src/components/ProjectKnowledgeFactEditor.tsx +++ b/apps/mobile/src/components/ProjectKnowledgeFactEditor.tsx @@ -58,6 +58,7 @@ export function ProjectKnowledgeFactEditor(props: { tags !== (base?.tags.join(", ") ?? "") || kind !== (base?.kind ?? "note"); const { onDirtyChange } = props; + // oxlint-disable-next-line t3code/no-unreasoned-state-sync -- keeps the parent's leave guard in step, including pre-filled drafts, and releases it on unmount useEffect(() => { onDirtyChange(dirty); return () => onDirtyChange(false); diff --git a/apps/web/src/components/codeExplorer/CodeExplorerDialogHost.tsx b/apps/web/src/components/codeExplorer/CodeExplorerDialogHost.tsx index 6bf2caeb90c25..aedba716dd374 100644 --- a/apps/web/src/components/codeExplorer/CodeExplorerDialogHost.tsx +++ b/apps/web/src/components/codeExplorer/CodeExplorerDialogHost.tsx @@ -21,6 +21,7 @@ export function CodeExplorerDialogHost(props: { readonly projectId: ProjectId; }) { const [request, setRequest] = useAtom(codeExplorerRequestAtom); + // oxlint-disable-next-line t3code/no-unreasoned-state-sync -- clears the keep-alive request atom on unmount so a stale request cannot reopen the dialog useEffect(() => () => setRequest(null), [setRequest]); const active = request !== null && diff --git a/apps/web/src/components/loom/LoomMinimap.tsx b/apps/web/src/components/loom/LoomMinimap.tsx index 96896ffef1239..13a7284736694 100644 --- a/apps/web/src/components/loom/LoomMinimap.tsx +++ b/apps/web/src/components/loom/LoomMinimap.tsx @@ -22,6 +22,7 @@ export function LoomMinimap(props: { }) { const ref = useRef(null); const [width, setWidth] = useState(0); + // oxlint-disable-next-line t3code/no-unreasoned-state-sync -- subscribes to this element's size through a ResizeObserver useLayoutEffect(() => { const element = ref.current; if (element === null) return; diff --git a/apps/web/src/components/loom/LoomTimeline.tsx b/apps/web/src/components/loom/LoomTimeline.tsx index a1bfb40146fff..655b8f77c1947 100644 --- a/apps/web/src/components/loom/LoomTimeline.tsx +++ b/apps/web/src/components/loom/LoomTimeline.tsx @@ -57,6 +57,7 @@ export interface LoomTimelineProps { function useElementWidth() { const ref = useRef(null); const [width, setWidth] = useState(0); + // oxlint-disable-next-line t3code/no-unreasoned-state-sync -- subscribes to this element's size through a ResizeObserver useLayoutEffect(() => { const element = ref.current; if (element === null) return; @@ -78,6 +79,7 @@ export function LoomTimeline(props: LoomTimelineProps) { const scale = loomScale(props.view, timelineWidth); const asOfMs = Date.parse(props.window.asOf); + // oxlint-disable-next-line t3code/no-unreasoned-state-sync -- subscribes to the scroller's height through a ResizeObserver to window visible rows useLayoutEffect(() => { const element = scrollRef.current; if (element === null) return; diff --git a/apps/web/src/components/loom/LoomWeaveField.tsx b/apps/web/src/components/loom/LoomWeaveField.tsx index cc74b047b8343..3b43c64c48574 100644 --- a/apps/web/src/components/loom/LoomWeaveField.tsx +++ b/apps/web/src/components/loom/LoomWeaveField.tsx @@ -65,6 +65,7 @@ export interface LoomWeaveFieldProps { function useElementSize() { const ref = useRef(null); const [size, setSize] = useState({ width: 0, height: 0 }); + // oxlint-disable-next-line t3code/no-unreasoned-state-sync -- subscribes to this element's size through a ResizeObserver useLayoutEffect(() => { const element = ref.current; if (element === null) return; @@ -452,7 +453,7 @@ function BranchLayer( const labelRoom = laneLabelRoom(paths, layout, width); const rootY = layout.cy; const { scrollRef } = props; - // A workstream taller than the field opens scrolled to its root, not to its topmost branch. + // oxlint-disable-next-line t3code/no-unreasoned-state-sync -- sets the DOM scroll position so a tall workstream opens on its root, not its topmost branch useLayoutEffect(() => { const element = scrollRef.current; if (element !== null) element.scrollTop = Math.max(0, rootY - element.clientHeight / 2); diff --git a/apps/web/src/components/loom/useLoomViewGestures.ts b/apps/web/src/components/loom/useLoomViewGestures.ts index 5e4399cd6d6c3..cdd6b25d268c5 100644 --- a/apps/web/src/components/loom/useLoomViewGestures.ts +++ b/apps/web/src/components/loom/useLoomViewGestures.ts @@ -31,7 +31,7 @@ export function useLoomViewGestures(args: { onViewChange(panLoomView(view, bounds, delta * scale.msPerPx)); } }); - // Wheel zoom needs preventDefault, which React's passive wheel listener cannot do. + // oxlint-disable-next-line t3code/no-unreasoned-state-sync -- attaches a non-passive wheel listener, since React's passive one cannot preventDefault for zoom useEffect(() => { const element = wheelRef.current; if (element === null) return;