fix: resolve all ESLint warnings, add zero-warnings enforcement#899
fix: resolve all ESLint warnings, add zero-warnings enforcement#899
Conversation
Replace useEffect-based state sync with render-phase patterns to fix set-state-in-effect warnings, use meaningful keys instead of array indices, add useMemo for impure render expressions, fix ref naming convention, and correct exhaustive-deps. Add ESLint zero-warnings pre-commit/pre-push hook for web/src files. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Memoize usePolling return value to prevent infinite stop/start cycle when used as useEffect dependency. Add --max-warnings 0 to npm lint script for CI parity with pre-commit hook. Restore index tiebreakers for event/criteria keys that lack natural unique identifiers. Update CLAUDE.md hook lists. Use npm run lint in hook entry. Pre-reviewed by 4 agents, 6 findings addressed Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
WalkthroughAdded a local Suggested labelsautorelease: tagged 🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Comment |
Dependency Review✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.Snapshot WarningsEnsure that dependencies are being submitted on PR branches. Re-running this action after a short time may resolve the issue. See the documentation for more information and troubleshooting advice. Scanned FilesNone |
There was a problem hiding this comment.
Code Review
This pull request introduces ESLint for the web dashboard, adding a pre-commit hook and enforcing zero warnings. It also refactors numerous React components to replace useEffect hooks with render-phase state updates using useRef for better performance and predictability. Additionally, it improves list rendering by using more stable keys and addresses several linting warnings across the web codebase. I have no feedback to provide as there were no review comments.
There was a problem hiding this comment.
Actionable comments posted: 15
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (4)
web/src/pages/setup/MiniOrgChart.tsx (1)
161-175: 🛠️ Refactor suggestion | 🟠 MajorExtract this
.map()render block into a shared subcomponent.This callback exceeds the project’s complexity rule for JSX inside
.map()and should be moved to a dedicated component/helper.As per coding guidelines: "Do not create complex (>8 line) JSX inside
.map()— extract to a shared component."🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@web/src/pages/setup/MiniOrgChart.tsx` around lines 161 - 175, The JSX callback passed to pos.dept.agents.map is too complex and should be extracted into a shared subcomponent; create a new component (e.g., AgentList or AgentRow) that accepts props: agents, deptX (pos.x), deptY (pos.y), AVATAR_RADIUS and V_GAP (or import constants), and inside that component compute agentX and agentY and render <AgentNode key={agent.name} agent={agent} agentX={agentX} agentY={agentY} deptX={deptX} deptY={deptY} /> for each agent; then replace the current pos.dept.agents.map block with a single call to the new subcomponent, keeping behavior and props identical.web/src/pages/org-edit/AgentEditDrawer.tsx (2)
47-60:⚠️ Potential issue | 🟠 MajorReset the delete dialog when the edited agent changes.
This block resets the form and
submitError, but it leavesdeleteOpen/deletinguntouched. If the drawer closes or switches agents while the confirm dialog is open, that modal can survive and start targeting the next loaded agent.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@web/src/pages/org-edit/AgentEditDrawer.tsx` around lines 47 - 60, When the edited agent changes (the block comparing agent to prevAgentRef.current that updates prevAgentRef, calls setForm and setSubmitError), also reset the delete-confirmation state so the previous agent's delete modal doesn't persist; call the state setters that control the confirm dialog (e.g., setDeleteOpen(false) and setDeleting(false)) inside that same branch where agent is truthy/updated so the delete dialog is closed and any in-progress delete is cleared whenever agent swaps.
47-60:⚠️ Potential issue | 🟠 MajorRender-time ref mutation can cause stale state in concurrent renders.
Lines 47–60 mutate
prevAgentRef.currentduring render and conditionally callsetFormandsetSubmitErrorbased on that mutation. React 19's concurrent rendering can interrupt and replay this render without rolling back the ref write, leaving it out of sync with state and causing stale form values or error state to persist.Replace this with a
useEffecthook that runs when theagentprop changes:useEffect(() => { if (agent) { setForm({ name: agent.name, role: agent.role, department: agent.department, level: agent.level, status: agent.status, }) setSubmitError(null) } }, [agent])🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@web/src/pages/org-edit/AgentEditDrawer.tsx` around lines 47 - 60, Render-time mutation of prevAgentRef.current and calling setForm/setSubmitError during render can cause stale state under concurrent React; move this logic into a useEffect that depends on agent. Replace the render-time block that references prevAgentRef and compares agent (symbols: prevAgentRef, agent, setForm, setSubmitError) with a useEffect(() => { if (agent) { setForm(...) ; setSubmitError(null) } }, [agent]) so updates run only when agent changes and avoid mutating refs during render.web/src/pages/org-edit/GeneralTab.tsx (1)
52-65:⚠️ Potential issue | 🟠 MajorDon't use render-time ref mutation for config→form synchronization.
Lines 53-65 mutate
prevConfigRef.currentduring render and conditionally callsetForm. React explicitly discourages render-time ref mutations; concurrent rendering can interrupt and replay the render, leaving the ref mutated whilesetFormnever commits. This causes form state to desync from the config prop. Move this logic into auseEffectwith dependencies[config, dirty]instead, ensuring the ref update and state sync happen together.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@web/src/pages/org-edit/GeneralTab.tsx` around lines 52 - 65, Move the render-time ref mutation and setForm call into a useEffect so updates and ref writes happen together: replace the current render-time block that mutates prevConfigRef.current and calls setForm with a useEffect that depends on [config, dirty]; inside the effect check if config !== prevConfigRef.current, set prevConfigRef.current = config, and if (config && !dirty) call setForm(...) populating company_name, autonomy_level (validate via VALID_AUTONOMY_LEVELS), budget_monthly (default 100), and communication_pattern (default 'hybrid') so synchronization is performed safely outside render.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.pre-commit-config.yaml:
- Around line 106-112: Update the pre-commit hook entry for id "eslint-web" to
avoid using a subshell and cd; change the entry that currently runs "bash -c
'(cd web && npm run lint)'" to use npm's --prefix option so it runs "npm
--prefix web run lint" (update the entry value for the eslint-web hook).
In `@web/src/components/ui/inline-edit.tsx`:
- Around line 44-50: The render mutates prevValueRef.current which is unsafe in
React 19; move that synchronization into a committed-effect: replace the inline
render-time mutation of prevValueRef.current and conditional setEditValue with a
useEffect (or useLayoutEffect if necessary for timing) that runs when value or
state change, compares value against prevValueRef.current, updates
prevValueRef.current, and calls setEditValue(value) when state === 'display'.
Update the logic around prevValueRef, state, setEditValue, and value to live
inside that effect so no ref.current is written during render.
In `@web/src/hooks/useBudgetData.ts`:
- Around line 63-66: The effect depends on the whole polling object which
changes identity and causes an infinite render loop; change the dependency to
use the stable start/stop callbacks (or an empty array with the lint exception
like the other hooks) — replace useEffect(..., [polling]) with useEffect(() => {
polling.start(); return () => polling.stop(); }, []) and add a single-line
eslint-disable-next-line react-hooks/exhaustive-deps comment above it (or
alternately depend on polling.start and polling.stop if those are stable
useCallback refs returned by usePolling) so only stable function refs are used.
In `@web/src/hooks/usePolling.ts`:
- Line 87: The returned polling object from usePolling currently includes active
and error in the useMemo deps, which makes its identity change whenever those
state values update and causes consumer effects that depend on the object to
loop; change the memoization so only the stable callbacks are dependencies (or
remove useMemo entirely) — keep the stable functions start and stop wrapped with
useCallback, remove active and error from the useMemo dependency list (or return
a plain object) and, if you need stable reads of active/error, expose refs
(e.g., activeRef/errorRef) or document consumers should depend on
polling.start/polling.stop instead of polling itself; update the usePolling
export accordingly so polling object identity is stable while state values are
still readable.
In `@web/src/pages/agents/ProseInsight.tsx`:
- Around line 21-22: The current mapping in the ProseInsight component uses the
insight string as the React key (inside the insights.map in ProseInsight.tsx),
which can produce duplicate keys when identical strings appear; change the key
to a composite that guarantees uniqueness (e.g., combine the insight value with
the index or another unique identifier such as `${insight}-${idx}`) or
explicitly fall back to the array index when no unique id exists so React keys
are stable and unique across renders.
In `@web/src/pages/ApprovalsPage.tsx`:
- Around line 139-146: The guard that closes batch dialogs when selectedIds
transitions to empty (using prevSelectionSizeRef.current and calls to
setBatchApproveOpen/setBatchRejectOpen/setBatchComment/setBatchReason) runs
during optimistic updates and closes dialogs while batchApprove is still
in-flight; update the condition so it only clears/closes when selectedIds.size
=== 0 AND batchLoading is false (i.e., gate the early-close on !batchLoading),
leaving prevSelectionSizeRef and the state resets intact but preventing
premature closure during optimistic batch operations.
In `@web/src/pages/org-edit/AgentCreateDialog.tsx`:
- Around line 41-47: The current render-time logic that checks
prevOpenRef.current and calls setForm, setErrors, and setSubmitError while
mutating prevOpenRef.current must be moved into a useEffect to preserve render
purity: create a useEffect with [open] dependency that compares
prevOpenRef.current to open, resets form state (use setForm(INITIAL_FORM),
setErrors({}), setSubmitError(null)) when the dialog transitions to closed, and
then update prevOpenRef.current = open inside the effect (alternatively simply
reset whenever !open in the same effect).
In `@web/src/pages/org-edit/DepartmentCreateDialog.tsx`:
- Around line 36-42: The render currently mutates prevOpenRef.current and resets
state during render (see prevOpenRef/useRef and the open check that calls
setForm(INITIAL_FORM), setErrors({}), setSubmitError(null)); move this logic
into a useEffect that watches the open value (e.g., useEffect(() => { if (!open
&& prevOpenRef.current) { ... } prevOpenRef.current = open }, [open])), or
alternatively perform the reset in the dialog's explicit close handler, so no
ref writes occur during render and the reset uses setForm, setErrors,
setSubmitError safely inside the effect/handler.
In `@web/src/pages/org-edit/DepartmentEditDrawer.tsx`:
- Around line 36-44: The department-change reset logic (using prevDepartmentRef
and department) updates display and error state but doesn't clear the
delete-modal state, so when department changes the destructive confirmation can
remain bound to the wrong entity; inside the branch where you setDisplayName,
setBudgetPercent, and setSubmitError (the same block guarded by
prevDepartmentRef/current and department), also call the modal state reset
functions (setDeleteOpen(false) and setDeleting(false)) to ensure deleteOpen and
deleting are cleared whenever the department changes.
- Around line 36-44: The department-change sync block that compares department
with prevDepartmentRef currently resets display and submit state (in the branch
that sets display name, budget percent and setSubmitError) but does not reset
delete dialog flags; update the same block (the code using prevDepartmentRef,
department, setDisplayName, setBudgetPercent, setSubmitError) to also call
setDeleteOpen(false) and setDeleting(false) so delete dialog state is cleared
whenever the department changes.
In `@web/src/pages/org-edit/YamlEditorPanel.tsx`:
- Around line 17-25: The render-time mutation of prevConfigRef should be moved
into a useEffect to avoid stale state when renders are interrupted: remove the
in-render block that compares and assigns prevConfigRef.current to config and
instead add useEffect(() => { if (config !== prevConfigRef.current) {
prevConfigRef.current = config; if (config && !dirty) {
setYamlText(serializeToYaml(config)); setDirty(false); setParseError(null); } }
}, [config, dirty]); so synchronization runs after commit and uses
serializeToYaml, setYamlText, setDirty, and setParseError as before; keep
prevConfigRef as a ref to track the last synced config.
In `@web/src/pages/providers/ProviderFormDrawer.tsx`:
- Around line 63-68: The guard is comparing preset objects by reference which
can flip true when the presets array is refreshed, wiping in-progress edits;
change the comparisons to use a stable unique key instead of object identity
(e.g., compare selectedPreset?.id or selectedPreset?.key and preset?.id) and
store those keys in prevPresetRef / prevSelectedPresetRef (or introduce
prevPresetIdRef / prevSelectedPresetIdRef) so that presetChanged and
selectedPresetChanged reflect real user selection changes rather than new object
instances; update the logic in the functions/variables named prevPresetRef,
prevSelectedPresetRef, presetChanged, and selectedPresetChanged (and the
analogous guards later in the file) to use the stable id comparison.
- Around line 61-68: mode/provider/preset "changed" flags are computed from
stale refs so reopening or switching modes doesn't rehydrate or clear fields
correctly; update logic to set and compare previous values inside a useEffect
that runs on provider, mode, preset, and selectedPreset changes (use
prevProviderRef, prevModeRef, prevPresetRef, prevSelectedPresetRef) so
modeChanged/providerChanged/presetChanged/selectedPresetChanged reflect real
transitions, and ensure handleClose resets both the form state and those prev*
refs; also when switching between create and edit clear sensitive fields
(selectedPreset, apiKey, subscriptionToken) on the mode transition (e.g., in the
same effect when mode changes) to avoid leaking previous credentials.
In `@web/src/pages/setup/AgentsStep.tsx`:
- Line 117: The StaggerItem currently uses agent.name as React key which can
change via handleNameChange and cause duplicate keys; change the key to a stable
composite (e.g., `${agent.id ?? index}-${index}` or simply use the provided
index as a fallback) so it won't collide when names are edited — update the
StaggerItem key prop where it is rendered (symbol: StaggerItem, variable: agent,
prop: name, callback: handleNameChange, available index param) to use a stable
identifier instead of raw agent.name.
In `@web/src/pages/setup/MiniOrgChart.tsx`:
- Line 167: The map callback in MiniOrgChart uses a non-unique key (agent.name)
and is too large; change the key to a collision-safe value like
`${agent.name}-${agentIdx}` and extract the JSX inside the .map into a new small
component (e.g., AgentNodeItem or AgentNodeRenderer) that accepts the agent,
agentIdx, department and any handlers/props used in the map and returns the
<AgentNode> markup; then replace the inline callback with a call to that
component and pass the new unique key. Ensure the new component is
typed/prop-validated consistently with MiniOrgChart and exported/defined near
the file bottom for testability and reuse.
---
Outside diff comments:
In `@web/src/pages/org-edit/AgentEditDrawer.tsx`:
- Around line 47-60: When the edited agent changes (the block comparing agent to
prevAgentRef.current that updates prevAgentRef, calls setForm and
setSubmitError), also reset the delete-confirmation state so the previous
agent's delete modal doesn't persist; call the state setters that control the
confirm dialog (e.g., setDeleteOpen(false) and setDeleting(false)) inside that
same branch where agent is truthy/updated so the delete dialog is closed and any
in-progress delete is cleared whenever agent swaps.
- Around line 47-60: Render-time mutation of prevAgentRef.current and calling
setForm/setSubmitError during render can cause stale state under concurrent
React; move this logic into a useEffect that depends on agent. Replace the
render-time block that references prevAgentRef and compares agent (symbols:
prevAgentRef, agent, setForm, setSubmitError) with a useEffect(() => { if
(agent) { setForm(...) ; setSubmitError(null) } }, [agent]) so updates run only
when agent changes and avoid mutating refs during render.
In `@web/src/pages/org-edit/GeneralTab.tsx`:
- Around line 52-65: Move the render-time ref mutation and setForm call into a
useEffect so updates and ref writes happen together: replace the current
render-time block that mutates prevConfigRef.current and calls setForm with a
useEffect that depends on [config, dirty]; inside the effect check if config !==
prevConfigRef.current, set prevConfigRef.current = config, and if (config &&
!dirty) call setForm(...) populating company_name, autonomy_level (validate via
VALID_AUTONOMY_LEVELS), budget_monthly (default 100), and communication_pattern
(default 'hybrid') so synchronization is performed safely outside render.
In `@web/src/pages/setup/MiniOrgChart.tsx`:
- Around line 161-175: The JSX callback passed to pos.dept.agents.map is too
complex and should be extracted into a shared subcomponent; create a new
component (e.g., AgentList or AgentRow) that accepts props: agents, deptX
(pos.x), deptY (pos.y), AVATAR_RADIUS and V_GAP (or import constants), and
inside that component compute agentX and agentY and render <AgentNode
key={agent.name} agent={agent} agentX={agentX} agentY={agentY} deptX={deptX}
deptY={deptY} /> for each agent; then replace the current pos.dept.agents.map
block with a single call to the new subcomponent, keeping behavior and props
identical.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 8a59931b-7be4-4ab3-abdb-77a8fa47f55a
📒 Files selected for processing (28)
.pre-commit-config.yamlCLAUDE.mdweb/package.jsonweb/src/components/ui/inline-edit.tsxweb/src/hooks/useBudgetData.tsweb/src/hooks/usePolling.tsweb/src/pages/ApprovalsPage.tsxweb/src/pages/LoginPage.tsxweb/src/pages/TaskDetailPage.tsxweb/src/pages/agents/ActivityLog.tsxweb/src/pages/agents/CareerTimeline.tsxweb/src/pages/agents/ProseInsight.tsxweb/src/pages/agents/ToolBadges.tsxweb/src/pages/approvals/ApprovalDetailDrawer.tsxweb/src/pages/org-edit/AgentCreateDialog.tsxweb/src/pages/org-edit/AgentEditDrawer.tsxweb/src/pages/org-edit/DepartmentCreateDialog.tsxweb/src/pages/org-edit/DepartmentEditDrawer.tsxweb/src/pages/org-edit/GeneralTab.tsxweb/src/pages/org-edit/YamlEditorPanel.tsxweb/src/pages/providers/ProviderFormDrawer.tsxweb/src/pages/providers/ProviderHealthMetrics.tsxweb/src/pages/setup/AccountStep.tsxweb/src/pages/setup/AgentsStep.tsxweb/src/pages/setup/MiniOrgChart.tsxweb/src/pages/setup/ProvidersStep.tsxweb/src/pages/setup/SetupSummary.tsxweb/src/pages/tasks/TaskDetailPanel.tsx
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
- GitHub Check: Dashboard Test
- GitHub Check: Build Sandbox
- GitHub Check: Build Backend
- GitHub Check: Build Web
- GitHub Check: Analyze (python)
- GitHub Check: Dependency Review
🧰 Additional context used
📓 Path-based instructions (8)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx}: Always reuse existing components fromweb/src/components/ui/before creating new ones. Refer to the Web Dashboard Design System component inventory (StatusBadge, MetricCard, Sparkline, SectionCard, AgentCard, DeptHealthBar, ProgressGauge, StatPill, Avatar, Button, Toast, Skeleton variants, EmptyState, ErrorBoundary, ConfirmDialog, CommandPalette, InlineEdit, AnimatedPresence, StaggerGroup/Item, Drawer, InputField, SelectField, SliderField, ToggleField, TaskStatusIndicator, PriorityBadge, ProviderHealthBadge) for all page compositions.
Use design tokens exclusively for colors, typography, spacing, shadows, and borders. Never hardcode hex values, rgba colors, fontFamily, or pixel values for layout spacing in .tsx/.ts files. Use Tailwind semantic classes (text-foreground, bg-card, text-accent, text-success, bg-danger) or CSS variables (var(--so-*)).
Use Hypothesis equivalent fast-check for property-based testing in React/TypeScript:fc.assert+fc.property.
Files:
web/src/pages/agents/ProseInsight.tsxweb/src/pages/tasks/TaskDetailPanel.tsxweb/src/hooks/usePolling.tsweb/src/pages/setup/AccountStep.tsxweb/src/pages/setup/MiniOrgChart.tsxweb/src/pages/agents/ToolBadges.tsxweb/src/pages/LoginPage.tsxweb/src/pages/setup/AgentsStep.tsxweb/src/pages/setup/ProvidersStep.tsxweb/src/pages/TaskDetailPage.tsxweb/src/pages/agents/ActivityLog.tsxweb/src/pages/org-edit/AgentCreateDialog.tsxweb/src/pages/org-edit/AgentEditDrawer.tsxweb/src/pages/agents/CareerTimeline.tsxweb/src/pages/org-edit/YamlEditorPanel.tsxweb/src/pages/org-edit/DepartmentCreateDialog.tsxweb/src/hooks/useBudgetData.tsweb/src/pages/org-edit/GeneralTab.tsxweb/src/pages/ApprovalsPage.tsxweb/src/components/ui/inline-edit.tsxweb/src/pages/approvals/ApprovalDetailDrawer.tsxweb/src/pages/org-edit/DepartmentEditDrawer.tsxweb/src/pages/providers/ProviderHealthMetrics.tsxweb/src/pages/providers/ProviderFormDrawer.tsxweb/src/pages/setup/SetupSummary.tsx
web/src/**/*.tsx
📄 CodeRabbit inference engine (CLAUDE.md)
web/src/**/*.tsx: Do not recreate inline status indicators — use<StatusBadge>. Do not build card-with-header layouts from scratch — use<SectionCard>. Do not create metric displays with inlinetext-metric font-bold— use<MetricCard>. Do not render initials circles manually — use<Avatar>. Do not create complex (>8 line) JSX inside.map()— extract to a shared component.
Use design token CSS variables exclusively for all spacing (p-card, gap-section-gap, gap-grid-gap), shadows (var(--so-shadow-card-hover)), and borders (border-border, border-bright). Never hardcode pixel values or color values in .tsx files.
Files:
web/src/pages/agents/ProseInsight.tsxweb/src/pages/tasks/TaskDetailPanel.tsxweb/src/pages/setup/AccountStep.tsxweb/src/pages/setup/MiniOrgChart.tsxweb/src/pages/agents/ToolBadges.tsxweb/src/pages/LoginPage.tsxweb/src/pages/setup/AgentsStep.tsxweb/src/pages/setup/ProvidersStep.tsxweb/src/pages/TaskDetailPage.tsxweb/src/pages/agents/ActivityLog.tsxweb/src/pages/org-edit/AgentCreateDialog.tsxweb/src/pages/org-edit/AgentEditDrawer.tsxweb/src/pages/agents/CareerTimeline.tsxweb/src/pages/org-edit/YamlEditorPanel.tsxweb/src/pages/org-edit/DepartmentCreateDialog.tsxweb/src/pages/org-edit/GeneralTab.tsxweb/src/pages/ApprovalsPage.tsxweb/src/components/ui/inline-edit.tsxweb/src/pages/approvals/ApprovalDetailDrawer.tsxweb/src/pages/org-edit/DepartmentEditDrawer.tsxweb/src/pages/providers/ProviderHealthMetrics.tsxweb/src/pages/providers/ProviderFormDrawer.tsxweb/src/pages/setup/SetupSummary.tsx
web/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Extract complex JSX blocks (>8 lines) from
.map()into separate shared components rather than inline JSX. This ensures reusability and testability of rendered list items and card contents.
Files:
web/src/pages/agents/ProseInsight.tsxweb/src/pages/tasks/TaskDetailPanel.tsxweb/src/hooks/usePolling.tsweb/src/pages/setup/AccountStep.tsxweb/src/pages/setup/MiniOrgChart.tsxweb/src/pages/agents/ToolBadges.tsxweb/src/pages/LoginPage.tsxweb/src/pages/setup/AgentsStep.tsxweb/src/pages/setup/ProvidersStep.tsxweb/src/pages/TaskDetailPage.tsxweb/src/pages/agents/ActivityLog.tsxweb/src/pages/org-edit/AgentCreateDialog.tsxweb/src/pages/org-edit/AgentEditDrawer.tsxweb/src/pages/agents/CareerTimeline.tsxweb/src/pages/org-edit/YamlEditorPanel.tsxweb/src/pages/org-edit/DepartmentCreateDialog.tsxweb/src/hooks/useBudgetData.tsweb/src/pages/org-edit/GeneralTab.tsxweb/src/pages/ApprovalsPage.tsxweb/src/components/ui/inline-edit.tsxweb/src/pages/approvals/ApprovalDetailDrawer.tsxweb/src/pages/org-edit/DepartmentEditDrawer.tsxweb/src/pages/providers/ProviderHealthMetrics.tsxweb/src/pages/providers/ProviderFormDrawer.tsxweb/src/pages/setup/SetupSummary.tsx
web/**/*.tsx
📄 CodeRabbit inference engine (CLAUDE.md)
web/**/*.tsx: Mount<ToastContainer>once in the AppLayout component as the single toast notification manager for all pages. Use the Toast component for success/error/warning/info notifications with auto-dismiss queue.
Use<ErrorBoundary>with thelevelprop (page/section/component) to provide appropriate error isolation and recovery for different component hierarchies.
Files:
web/src/pages/agents/ProseInsight.tsxweb/src/pages/tasks/TaskDetailPanel.tsxweb/src/pages/setup/AccountStep.tsxweb/src/pages/setup/MiniOrgChart.tsxweb/src/pages/agents/ToolBadges.tsxweb/src/pages/LoginPage.tsxweb/src/pages/setup/AgentsStep.tsxweb/src/pages/setup/ProvidersStep.tsxweb/src/pages/TaskDetailPage.tsxweb/src/pages/agents/ActivityLog.tsxweb/src/pages/org-edit/AgentCreateDialog.tsxweb/src/pages/org-edit/AgentEditDrawer.tsxweb/src/pages/agents/CareerTimeline.tsxweb/src/pages/org-edit/YamlEditorPanel.tsxweb/src/pages/org-edit/DepartmentCreateDialog.tsxweb/src/pages/org-edit/GeneralTab.tsxweb/src/pages/ApprovalsPage.tsxweb/src/components/ui/inline-edit.tsxweb/src/pages/approvals/ApprovalDetailDrawer.tsxweb/src/pages/org-edit/DepartmentEditDrawer.tsxweb/src/pages/providers/ProviderHealthMetrics.tsxweb/src/pages/providers/ProviderFormDrawer.tsxweb/src/pages/setup/SetupSummary.tsx
web/src/pages/**/*.tsx
📄 CodeRabbit inference engine (CLAUDE.md)
Lazy-load page components via React Router. Page-scoped sub-components should be placed in
pages/<page-name>/subdirectories (e.g., pages/tasks/, pages/org-edit/) to keep the component tree organized.
Files:
web/src/pages/agents/ProseInsight.tsxweb/src/pages/tasks/TaskDetailPanel.tsxweb/src/pages/setup/AccountStep.tsxweb/src/pages/setup/MiniOrgChart.tsxweb/src/pages/agents/ToolBadges.tsxweb/src/pages/LoginPage.tsxweb/src/pages/setup/AgentsStep.tsxweb/src/pages/setup/ProvidersStep.tsxweb/src/pages/TaskDetailPage.tsxweb/src/pages/agents/ActivityLog.tsxweb/src/pages/org-edit/AgentCreateDialog.tsxweb/src/pages/org-edit/AgentEditDrawer.tsxweb/src/pages/agents/CareerTimeline.tsxweb/src/pages/org-edit/YamlEditorPanel.tsxweb/src/pages/org-edit/DepartmentCreateDialog.tsxweb/src/pages/org-edit/GeneralTab.tsxweb/src/pages/ApprovalsPage.tsxweb/src/pages/approvals/ApprovalDetailDrawer.tsxweb/src/pages/org-edit/DepartmentEditDrawer.tsxweb/src/pages/providers/ProviderHealthMetrics.tsxweb/src/pages/providers/ProviderFormDrawer.tsxweb/src/pages/setup/SetupSummary.tsx
web/package.json
📄 CodeRabbit inference engine (CLAUDE.md)
Require Node.js 22+, TypeScript 6.0+. Core dependencies: React 19, react-router, shadcn/ui, Radix UI, Tailwind CSS 4, Zustand,
@tanstack/react-query,@xyflow/react,@dagrejs/dagre,@dnd-kit, Recharts, Framer Motion, cmdk, Axios, Lucide React,@fontsource-variable/geist,@fontsource-variable/geist-mono. Dev/test: Storybook 10, Vitest, fast-check, ESLint,@eslint-react/eslint-plugin, eslint-plugin-security.
Files:
web/package.json
**/*.md
📄 CodeRabbit inference engine (CLAUDE.md)
When a spec topic is referenced (e.g., 'the Agents page' or 'the Engine page's Crash Recovery section'), read the relevant
docs/design/page before coding. When approved deviations occur, update the relevantdocs/design/page to reflect the new reality.
Files:
CLAUDE.md
web/src/components/ui/**/*.tsx
📄 CodeRabbit inference engine (CLAUDE.md)
web/src/components/ui/**/*.tsx: Every new shared component inweb/src/components/ui/must have a corresponding.stories.tsxStorybook file documenting all states (default, hover, loading, error, empty) alongside the component file.
Export component props as a TypeScript interface. Use design tokens exclusively — no hardcoded colors, fonts, or spacing. Importcnfrom@/lib/utilsfor conditional class merging.
Files:
web/src/components/ui/inline-edit.tsx
🧠 Learnings (27)
📓 Common learnings
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T12:42:32.168Z
Learning: Never create a PR directly — use `/pre-pr-review` to create PRs (runs automated checks + review agents + fixes). For trivial/docs-only changes, use `/pre-pr-review quick` to skip agents but still run automated checks. After the PR exists, use `/aurelio-review-pr` for external reviewer feedback. Fix all valid review findings, including pre-existing adjacent issues.
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:49:53.264Z
Learning: Fix everything valid — never skip when review agents find valid issues (including pre-existing issues in surrounding code, suggestions, and findings adjacent to the PR's changes). No deferring, no 'out of scope' skipping.
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T12:00:18.113Z
Learning: Commits: <type>: <description> — types: feat, fix, refactor, docs, test, chore, perf, ci. Enforced by commitizen (commit-msg hook). Signed commits: required on main via branch protection — all commits must be GPG/SSH signed.
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T12:42:32.168Z
Learning: Applies to web/src/**/*.{ts,tsx} : Extract complex JSX blocks (>8 lines) from `.map()` into separate shared components rather than inline JSX. This ensures reusability and testability of rendered list items and card contents.
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T12:42:32.168Z
Learning: Applies to web/src/**/*.tsx : Do not recreate inline status indicators — use `<StatusBadge>`. Do not build card-with-header layouts from scratch — use `<SectionCard>`. Do not create metric displays with inline `text-metric font-bold` — use `<MetricCard>`. Do not render initials circles manually — use `<Avatar>`. Do not create complex (>8 line) JSX inside `.map()` — extract to a shared component.
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T12:42:32.168Z
Learning: Applies to web/package.json : Require Node.js 22+, TypeScript 6.0+. Core dependencies: React 19, react-router, shadcn/ui, Radix UI, Tailwind CSS 4, Zustand, tanstack/react-query, xyflow/react, dagrejs/dagre, dnd-kit, Recharts, Framer Motion, cmdk, Axios, Lucide React, fontsource-variable/geist, fontsource-variable/geist-mono. Dev/test: Storybook 10, Vitest, fast-check, ESLint, eslint-react/eslint-plugin, eslint-plugin-security.
📚 Learning: 2026-03-28T12:42:32.168Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T12:42:32.168Z
Learning: Applies to web/src/**/*.{ts,tsx} : Extract complex JSX blocks (>8 lines) from `.map()` into separate shared components rather than inline JSX. This ensures reusability and testability of rendered list items and card contents.
Applied to files:
web/src/pages/agents/ProseInsight.tsxweb/src/pages/tasks/TaskDetailPanel.tsxweb/src/pages/setup/MiniOrgChart.tsxweb/src/pages/agents/ToolBadges.tsxweb/src/pages/setup/AgentsStep.tsxweb/src/pages/TaskDetailPage.tsxweb/src/pages/ApprovalsPage.tsxweb/src/components/ui/inline-edit.tsxweb/src/pages/approvals/ApprovalDetailDrawer.tsx
📚 Learning: 2026-03-28T12:42:32.168Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T12:42:32.168Z
Learning: Applies to web/src/**/*.tsx : Do not recreate inline status indicators — use `<StatusBadge>`. Do not build card-with-header layouts from scratch — use `<SectionCard>`. Do not create metric displays with inline `text-metric font-bold` — use `<MetricCard>`. Do not render initials circles manually — use `<Avatar>`. Do not create complex (>8 line) JSX inside `.map()` — extract to a shared component.
Applied to files:
web/src/pages/agents/ProseInsight.tsxweb/src/pages/tasks/TaskDetailPanel.tsxweb/src/pages/setup/MiniOrgChart.tsxweb/src/pages/agents/ToolBadges.tsxweb/src/pages/setup/AgentsStep.tsxweb/src/pages/TaskDetailPage.tsxweb/src/pages/agents/ActivityLog.tsxweb/src/pages/org-edit/AgentEditDrawer.tsxweb/src/pages/agents/CareerTimeline.tsxweb/src/pages/org-edit/GeneralTab.tsxweb/src/pages/ApprovalsPage.tsxweb/src/components/ui/inline-edit.tsxweb/src/pages/approvals/ApprovalDetailDrawer.tsxweb/src/pages/providers/ProviderHealthMetrics.tsxweb/src/pages/providers/ProviderFormDrawer.tsx
📚 Learning: 2026-03-14T15:43:05.601Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-14T15:43:05.601Z
Learning: Applies to web/package.json : Web dashboard Node.js 20+; dependencies in web/package.json (Vue 3, PrimeVue, Tailwind CSS, Pinia, VueFlow, ECharts, Axios, vue-draggable-plus, Vitest, ESLint, vue-tsc)
Applied to files:
web/package.json
📚 Learning: 2026-03-28T12:42:32.168Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T12:42:32.168Z
Learning: Applies to web/tsconfig.json : TypeScript 6.0+: Remove deprecated `baseUrl` (use `paths` relative to tsconfig directory). Remove explicit `esModuleInterop: true` (now default, non-editable). Set `types: []` and explicitly list needed types (e.g., `vitest/globals`). Use `DOM` lib (no separate `DOM.Iterable`). Use `moduleResolution: bundler` or `nodenext` (no `classic` or `node10`). `strict: true` is default. `noUncheckedSideEffectImports: true` is default (CSS imports need type declarations via `/// <reference types="vite/client" />`).
Applied to files:
web/package.json.pre-commit-config.yaml
📚 Learning: 2026-03-19T11:30:29.217Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:30:29.217Z
Learning: Applies to cli/**/*.go : Run Go lint via `golangci-lint run`, vet via `go vet`, tests via `go test ./...`, and fuzz via `go test -fuzz=FuzzTarget -fuzztime=30s`
Applied to files:
web/package.json.pre-commit-config.yaml
📚 Learning: 2026-03-20T08:28:32.845Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-20T08:28:32.845Z
Learning: Applies to web/src/__tests__/**/*.{ts,js} : Dashboard testing: Vitest unit tests organized by feature under `web/src/__tests__/`. Use fast-check for property-based testing (`fc.assert` + `fc.property`).
Applied to files:
web/package.json
📚 Learning: 2026-03-21T12:54:22.557Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-21T12:54:22.557Z
Learning: Applies to cli/**/*.go : Run Go lint via `golangci-lint run`, vet via `go vet ./...`, tests via `go test ./...` from the `cli/` directory (Go module root)
Applied to files:
web/package.json
📚 Learning: 2026-03-28T12:42:32.168Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T12:42:32.168Z
Learning: Applies to **/*.{ts,tsx} : Always reuse existing components from `web/src/components/ui/` before creating new ones. Refer to the Web Dashboard Design System component inventory (StatusBadge, MetricCard, Sparkline, SectionCard, AgentCard, DeptHealthBar, ProgressGauge, StatPill, Avatar, Button, Toast, Skeleton variants, EmptyState, ErrorBoundary, ConfirmDialog, CommandPalette, InlineEdit, AnimatedPresence, StaggerGroup/Item, Drawer, InputField, SelectField, SliderField, ToggleField, TaskStatusIndicator, PriorityBadge, ProviderHealthBadge) for all page compositions.
Applied to files:
web/src/pages/agents/ToolBadges.tsxweb/src/pages/org-edit/AgentEditDrawer.tsxweb/src/pages/org-edit/GeneralTab.tsxweb/src/pages/org-edit/DepartmentEditDrawer.tsx
📚 Learning: 2026-03-28T12:42:32.168Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T12:42:32.168Z
Learning: Applies to web/src/components/ui/**/*.tsx : Export component props as a TypeScript interface. Use design tokens exclusively — no hardcoded colors, fonts, or spacing. Import `cn` from `@/lib/utils` for conditional class merging.
Applied to files:
web/src/pages/agents/ToolBadges.tsxweb/src/pages/org-edit/AgentCreateDialog.tsxweb/src/pages/org-edit/DepartmentCreateDialog.tsxweb/src/pages/org-edit/GeneralTab.tsxweb/src/pages/ApprovalsPage.tsx
📚 Learning: 2026-03-28T12:42:32.168Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T12:42:32.168Z
Learning: Applies to web/package.json : Require Node.js 22+, TypeScript 6.0+. Core dependencies: React 19, react-router, shadcn/ui, Radix UI, Tailwind CSS 4, Zustand, tanstack/react-query, xyflow/react, dagrejs/dagre, dnd-kit, Recharts, Framer Motion, cmdk, Axios, Lucide React, fontsource-variable/geist, fontsource-variable/geist-mono. Dev/test: Storybook 10, Vitest, fast-check, ESLint, eslint-react/eslint-plugin, eslint-plugin-security.
Applied to files:
web/src/pages/org-edit/AgentCreateDialog.tsxweb/src/pages/org-edit/AgentEditDrawer.tsxweb/src/pages/org-edit/YamlEditorPanel.tsxweb/src/pages/org-edit/DepartmentCreateDialog.tsxweb/src/pages/org-edit/GeneralTab.tsxweb/src/pages/ApprovalsPage.tsxweb/src/pages/org-edit/DepartmentEditDrawer.tsxweb/src/pages/providers/ProviderFormDrawer.tsx
📚 Learning: 2026-03-28T12:42:32.168Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T12:42:32.168Z
Learning: Applies to web/src/stores/**/*.ts : Use Zustand stores for global state management: auth, WebSocket, toast, analytics, setup wizard, company, agents, budget, tasks, settings, providers, and per-domain stores for each page.
Applied to files:
web/src/pages/org-edit/AgentEditDrawer.tsx
📚 Learning: 2026-03-28T12:42:32.168Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T12:42:32.168Z
Learning: Applies to web/src/pages/**/*.tsx : Lazy-load page components via React Router. Page-scoped sub-components should be placed in `pages/<page-name>/` subdirectories (e.g., pages/tasks/, pages/org-edit/) to keep the component tree organized.
Applied to files:
web/src/pages/org-edit/GeneralTab.tsxweb/src/pages/org-edit/DepartmentEditDrawer.tsx
📚 Learning: 2026-03-28T12:42:32.168Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T12:42:32.168Z
Learning: Applies to .storybook/**/*.{ts,tsx} : Storybook 10 (ESM-only): Use `defineMain` from `storybook/react-vite/node` (main.ts) and `definePreview` from `storybook/react-vite` (preview.tsx). Essentials (backgrounds, controls, viewport, actions, toolbars, measure, outline) are built-in; if using `tags: ['autodocs']` or MDX, install `storybook/addon-docs`. Import from `storybook/test` (not `storybook/test`), `storybook/actions` (not `storybook/addon-actions`). Use `parameters.backgrounds.options` (object keyed by name) + `initialGlobals.backgrounds.value`. Set `parameters.a11y.test: 'error' | 'todo' | 'off'` globally to enforce WCAG compliance.
Applied to files:
web/src/pages/ApprovalsPage.tsx
📚 Learning: 2026-03-15T18:17:43.675Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Pre-commit hooks: trailing-whitespace, end-of-file-fixer, check-yaml, check-toml, check-json, check-merge-conflict, check-added-large-files, no-commit-to-branch (main), ruff check+format, gitleaks, hadolint (Dockerfile linting).
Applied to files:
CLAUDE.md.pre-commit-config.yaml
📚 Learning: 2026-03-15T12:00:18.113Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T12:00:18.113Z
Learning: Commits: <type>: <description> — types: feat, fix, refactor, docs, test, chore, perf, ci. Enforced by commitizen (commit-msg hook). Signed commits: required on main via branch protection — all commits must be GPG/SSH signed.
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-15T18:17:43.675Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Pre-push hooks: mypy type-check + pytest unit tests + golangci-lint + go vet + go test (CLI, conditional on cli/**/*.go) (fast gate before push, skipped in pre-commit.ci — dedicated CI jobs already run these).
Applied to files:
CLAUDE.md.pre-commit-config.yaml
📚 Learning: 2026-03-28T12:42:32.168Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T12:42:32.168Z
Learning: Use commit type prefixes: `feat:`, `fix:`, `refactor:`, `docs:`, `test:`, `chore:`, `perf:`, `ci:`. Pre-1.0 version bumping: `fix:`/`feat:` = patch, `feat!:`/`BREAKING CHANGE` = minor. Signed commits required on main via branch protection.
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-19T11:19:40.044Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:19:40.044Z
Learning: CLI workflow (`.github/workflows/cli.yml`) runs Go lint (golangci-lint + go vet) + test (race, coverage) + build (cross-compile matrix) + vulnerability check (govulncheck) + fuzz testing. Cross-compiles for linux/darwin/windows × amd64/arm64. GoReleaser release on v* tags with cosign keyless signing and SLSA L3 attestations.
Applied to files:
CLAUDE.md.pre-commit-config.yaml
📚 Learning: 2026-03-15T21:32:02.880Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to .github/workflows/cli.yml : CLI workflow: Go lint (golangci-lint + go vet) + test (-race -coverprofile) + build (cross-compile: linux/darwin/windows × amd64/arm64) + govulncheck + fuzz testing (main-only, 30s/target, continue-on-error, matrix over 4 packages). cli-pass gate includes fuzz as informational. GoReleaser release on v* tags. Cosign keyless signing of checksums.txt. SLSA L3 provenance attestations. Sigstore bundle (.sigstore.json) attached. Post-release appends checksums/verification/provenance to draft release notes.
Applied to files:
CLAUDE.md.pre-commit-config.yaml
📚 Learning: 2026-03-21T14:12:17.848Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-21T14:12:17.848Z
Learning: CLI workflow (`cli.yml`): Go lint/test/build (cross-compile) + govulncheck + fuzz. GoReleaser release on `v*` tags with cosign signing + SLSA provenance
Applied to files:
CLAUDE.md.pre-commit-config.yaml
📚 Learning: 2026-03-15T21:32:02.880Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to .github/workflows/docker.yml : Docker workflow: builds backend + web + sandbox images, pushes to GHCR, signs with cosign. SLSA L3 provenance attestations via actions/attest-build-provenance. Scans: Trivy (CRITICAL = hard fail, HIGH = warn) + Grype (critical cutoff) + CIS Docker Benchmark v1.6.0 compliance (informational). CVE triage via .github/.trivyignore.yaml and .github/.grype.yaml. Images only pushed after scans pass. Triggers on push to main and version tags (v*).
Applied to files:
CLAUDE.md.pre-commit-config.yaml
📚 Learning: 2026-03-20T12:59:09.553Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-20T12:59:09.553Z
Learning: NEVER create a PR directly — `gh pr create` is blocked by hookify. ALWAYS use `/pre-pr-review` to create PRs — it runs automated checks + review agents + fixes before creating the PR. For trivial/docs-only changes: `/pre-pr-review quick` skips agents but still runs automated checks.
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-28T12:42:32.168Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T12:42:32.168Z
Learning: Applies to .github/workflows/**/*.yml : Use `dorny/paths-filter` for path-based job filtering — jobs only run when their domain is affected. CLI has its own workflow (cli.yml). Coverage minimum: 80% (enforced in CI). All pre-commit hooks and pre-push checks run in CI but pre-push hooks are skipped in pre-commit.ci.
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-16T19:52:03.656Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-16T19:52:03.656Z
Learning: Applies to cli/**/*.go : Lint CLI Go code with golangci-lint and go vet; test with go test -race; check vulnerabilities with govulncheck
Applied to files:
.pre-commit-config.yaml
📚 Learning: 2026-03-15T12:00:18.113Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T12:00:18.113Z
Learning: Applies to .github/workflows/docker.yml : CI Docker: build → scan → push to GHCR + cosign sign + SLSA L3 provenance via attest-build-provenance (images only pushed after Trivy/Grype scans pass).
Applied to files:
.pre-commit-config.yaml
📚 Learning: 2026-03-21T14:12:17.848Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-21T14:12:17.848Z
Learning: Docker workflow (`docker.yml`): build + Trivy/Grype scan + push to GHCR + cosign sign + SLSA L3 provenance. CVE triage: `.github/.trivyignore.yaml`, `.github/.grype.yaml`
Applied to files:
.pre-commit-config.yaml
🔇 Additional comments (18)
web/src/pages/setup/ProvidersStep.tsx (1)
55-55: Ref rename and one-time probe guard update look correct.
probeAttemptedRefis used consistently, and the auto-probe gate logic remains intact for once-per-mount behavior.Also applies to: 73-74
web/src/pages/providers/ProviderHealthMetrics.tsx (2)
1-1: React import update is correct.
useMemois imported and used, so this change is clean and consistent.
11-16: Memoization boundary looks right.
lastChecknow recomputes only whenhealth.last_check_timestampchanges, which is the correct dependency scope.web/src/pages/setup/AccountStep.tsx (1)
34-35: Scoped suppression is justified and well-contained.This keeps the false-positive lint rule disable local to the client-side self-input comparison without weakening broader security lint coverage.
web/src/pages/LoginPage.tsx (1)
79-83: Good setup-flow validation addition with precise lint suppression.The confirm-password check correctly blocks invalid submission, and the eslint disable remains tightly scoped to this known client-side false positive.
web/src/pages/agents/ActivityLog.tsx (1)
41-42: LGTM!The eslint-disable comment is well-justified. Since events lack unique IDs and
event_type+timestampcan collide for same-second events, using the index as a tiebreaker is the correct approach. The inline comment clearly documents the rationale.web/src/pages/tasks/TaskDetailPanel.tsx (1)
260-261: LGTM!The composite key
${criterion.description}-${idx}with the eslint-disable is appropriate since acceptance criteria lack unique IDs and descriptions can duplicate. The inline comment documents the rationale.web/src/pages/agents/CareerTimeline.tsx (1)
25-26: LGTM!Consistent with the pattern used in
ActivityLog.tsx. The eslint-disable is justified for the same reason: career events lack unique IDs andevent_type+timestampmay collide.web/src/pages/ApprovalsPage.tsx (1)
59-61: LGTM!Valid render-phase state update pattern. Setting
wasConnectedduring render whenwsConnectedbecomes true avoids unnecessary useEffect overhead. React handles this correctly in React 18+.web/src/pages/approvals/ApprovalDetailDrawer.tsx (3)
70-79: LGTM!Clean render-phase pattern for resetting dialog state when the displayed approval changes. Using
useRefto track the previous ID and conditionally resetting state during render is the correct approach to replace the previous useEffect.
82-89: LGTM!Correct implementation of a pending→non-pending transition guard. The pattern properly detects the transition (not just the current state) and closes confirm dialogs when an approval is decided via WebSocket or other external update.
148-148: LGTM!Proper dependency list for the focus trap effect. The effect correctly re-runs when
loadingorapprovalchanges to capture newly rendered focusable elements after content loads.web/src/pages/setup/SetupSummary.tsx (1)
98-99:⚠️ Potential issue | 🟡 MinorUse array index as key instead of
agent.nameto avoid React warnings and incorrect DOM reconciliation.
SetupAgentSummaryhas no unique ID field, andupdateAgentNameallows renaming without uniqueness validation. If two agents share the same name, React will log duplicate key warnings. Use the array index instead (asCostEstimatePaneldoes withagentIndex), or introduce a unique identifier on the agent object.Current code at lines 98-99
{agents.map((agent) => ( <SetupAgentRow key={agent.name} agent={agent} />⛔ Skipped due to learnings
Learnt from: CR Repo: Aureliolo/synthorg PR: 0 File: CLAUDE.md:0-0 Timestamp: 2026-03-28T12:42:32.168Z Learning: Applies to web/src/**/*.tsx : Do not recreate inline status indicators — use `<StatusBadge>`. Do not build card-with-header layouts from scratch — use `<SectionCard>`. Do not create metric displays with inline `text-metric font-bold` — use `<MetricCard>`. Do not render initials circles manually — use `<Avatar>`. Do not create complex (>8 line) JSX inside `.map()` — extract to a shared component.Learnt from: CR Repo: Aureliolo/synthorg PR: 0 File: CLAUDE.md:0-0 Timestamp: 2026-03-28T12:42:32.168Z Learning: Applies to **/*.{ts,tsx} : Always reuse existing components from `web/src/components/ui/` before creating new ones. Refer to the Web Dashboard Design System component inventory (StatusBadge, MetricCard, Sparkline, SectionCard, AgentCard, DeptHealthBar, ProgressGauge, StatPill, Avatar, Button, Toast, Skeleton variants, EmptyState, ErrorBoundary, ConfirmDialog, CommandPalette, InlineEdit, AnimatedPresence, StaggerGroup/Item, Drawer, InputField, SelectField, SliderField, ToggleField, TaskStatusIndicator, PriorityBadge, ProviderHealthBadge) for all page compositions.web/package.json (1)
10-10: Good zero-warning lint gate.This is a solid enforcement change and matches the PR’s stated objective for warning-free linting in automation.
CLAUDE.md (1)
351-352: Docs update is consistent with hook enforcement changes.The new
eslint-webhook documentation is clear and aligned with the config updates in this PR.web/src/pages/TaskDetailPage.tsx (1)
222-223: Scoped suppression and collision-resistant fallback are appropriate here.The disable is narrowly scoped to one line, and the composite key avoids same-description collisions when criteria lack IDs.
.pre-commit-config.yaml (1)
5-5: CI skip update is consistent with the new local hook.Adding
eslint-webtoci.skipis coherent with your existing CI strategy.web/src/pages/agents/ToolBadges.tsx (1)
31-32: Use compound key to prevent badge reconciliation bugs when tool names repeat.Line 32 uses
toolas the key, butreadonly string[]does not guarantee uniqueness. If the tools array contains duplicate names, React will collide keys and may reconcile badge rows incorrectly.🔧 Proposed fix
- {tools.map((tool) => ( - <ToolBadge key={tool} tool={tool} /> + {tools.map((tool, idx) => ( + // eslint-disable-next-line `@eslint-react/no-array-index-key` -- tool labels may repeat + <ToolBadge key={`${tool}-${idx}`} tool={tool} /> ))}
| const prevValueRef = useRef(value) | ||
| useEffect(() => { | ||
| if (value !== prevValueRef.current && state === 'display') { | ||
| if (value !== prevValueRef.current) { | ||
| prevValueRef.current = value | ||
| if (state === 'display') { | ||
| setEditValue(value) | ||
| } | ||
| prevValueRef.current = value | ||
| }, [value, state]) | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
React 19 docs: is writing ref.current during render supported, and what render-phase pattern is recommended for syncing local state from prop changes?
💡 Result:
No, writing ref.current during render is not supported in React 19. The official React documentation explicitly states: "Do not write or read ref.current during rendering, except for initialization. This makes your component's behavior unpredictable." This rule holds in React 19, as confirmed in the current useRef docs. The recommended render-phase pattern for syncing local state (including refs) from prop changes is a guarded initialization check during render, allowed only for one-time setup: function VideoPlayer({ src }) { const playerRef = useRef(null); if (playerRef.current === null) { playerRef.current = new VideoPlayer(src); // Only runs once } else { playerRef.current.load(src); // Safe to call during render for updates } // ... } However, for general prop-to-local-state syncing (e.g., non-ref state or frequent updates), use useEffect instead: useEffect( => { localStateRef.current = newProp; }, [newProp]); This ensures synchronization happens after render/commit, avoiding render-phase side effects. The initialization pattern is a narrow exception for expensive object creation that should only happen once.
Citations:
- 1: https://react.dev/reference/react/useRef
- 2: https://beta.reactjs.org/reference/react/useRef
- 3: https://react.dev/learn/referencing-values-with-refs
- 4: https://react.dev/learn/sharing-state-between-components
🏁 Script executed:
# Check the full inline-edit.tsx file to understand the component logic
wc -l web/src/components/ui/inline-edit.tsxRepository: Aureliolo/synthorg
Length of output: 103
🏁 Script executed:
# Read the full inline-edit.tsx file
cat -n web/src/components/ui/inline-edit.tsxRepository: Aureliolo/synthorg
Length of output: 6786
🏁 Script executed:
# Search for other uses of prevValueRef in the file
rg "prevValueRef" web/src/components/ui/inline-edit.tsxRepository: Aureliolo/synthorg
Length of output: 171
🏁 Script executed:
# Check the callers mentioned in the review to confirm they pass async-backed values
cat -n web/src/pages/TaskDetailPage.tsx | sed -n '118,130p'Repository: Aureliolo/synthorg
Length of output: 793
🏁 Script executed:
# Check the second caller
cat -n web/src/pages/tasks/TaskDetailPanel.tsx | sed -n '142,154p'Repository: Aureliolo/synthorg
Length of output: 766
🏁 Script executed:
# Check the third caller
cat -n web/src/pages/setup/SetupAgentCard.tsx | sed -n '18,36p'Repository: Aureliolo/synthorg
Length of output: 783
Use committed state here; render-phase ref mutation is unsafe in React 19.
Lines 44–50 mutate prevValueRef.current during render. React 19 explicitly prohibits writing ref.current during render outside of one-time initialization. This pattern repeats the mutation on every render where value changes, violating React's render purity rules. An interrupted render can advance the ref even though that render never commits, causing a later committed render to skip the setEditValue sync. This is especially problematic here since the callers—TaskDetailPage, TaskDetailPanel, and SetupAgentCard—all pass store-backed values that change asynchronously after onSave.
Compare against committed state instead:
♻️ Proposed fix
- const prevValueRef = useRef(value)
- if (value !== prevValueRef.current) {
- prevValueRef.current = value
- if (state === 'display') {
- setEditValue(value)
- }
- }
+ if (state === 'display' && value !== editValue) {
+ setEditValue(value)
+ }📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const prevValueRef = useRef(value) | |
| useEffect(() => { | |
| if (value !== prevValueRef.current && state === 'display') { | |
| if (value !== prevValueRef.current) { | |
| prevValueRef.current = value | |
| if (state === 'display') { | |
| setEditValue(value) | |
| } | |
| prevValueRef.current = value | |
| }, [value, state]) | |
| } | |
| if (state === 'display' && value !== editValue) { | |
| setEditValue(value) | |
| } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@web/src/components/ui/inline-edit.tsx` around lines 44 - 50, The render
mutates prevValueRef.current which is unsafe in React 19; move that
synchronization into a committed-effect: replace the inline render-time mutation
of prevValueRef.current and conditional setEditValue with a useEffect (or
useLayoutEffect if necessary for timing) that runs when value or state change,
compares value against prevValueRef.current, updates prevValueRef.current, and
calls setEditValue(value) when state === 'display'. Update the logic around
prevValueRef, state, setEditValue, and value to live inside that effect so no
ref.current is written during render.
| const prevConfigRef = useRef<typeof config | undefined>(undefined) | ||
| if (config !== prevConfigRef.current) { | ||
| prevConfigRef.current = config | ||
| if (config && !dirty) { | ||
| const serialized = serializeToYaml(config) | ||
| setYamlText(serialized) | ||
| setYamlText(serializeToYaml(config)) | ||
| setDirty(false) | ||
| setParseError(null) | ||
| } | ||
| // eslint-disable-next-line @eslint-react/exhaustive-deps -- intentionally exclude dirty to avoid infinite loop | ||
| }, [config]) | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cat -n web/src/pages/org-edit/YamlEditorPanel.tsxRepository: Aureliolo/synthorg
Length of output: 3337
🏁 Script executed:
fd -type f package.json | head -5Repository: Aureliolo/synthorg
Length of output: 232
🏁 Script executed:
fd package.json | head -1 | xargs cat | grep -A 5 '"react"'Repository: Aureliolo/synthorg
Length of output: 44
🏁 Script executed:
cat package.json 2>/dev/null | head -30Repository: Aureliolo/synthorg
Length of output: 44
🏁 Script executed:
git log --oneline web/src/pages/org-edit/YamlEditorPanel.tsx | head -5Repository: Aureliolo/synthorg
Length of output: 142
🏁 Script executed:
git show 60144f9 -- web/src/pages/org-edit/YamlEditorPanel.tsx | head -100Repository: Aureliolo/synthorg
Length of output: 3752
🏁 Script executed:
git log --all --oneline --grep="config-sync\|YamlEditor" | head -10Repository: Aureliolo/synthorg
Length of output: 44
🏁 Script executed:
git log --all --oneline -- web/src/pages/org-edit/YamlEditorPanel.tsxRepository: Aureliolo/synthorg
Length of output: 206
🏁 Script executed:
git show cfb88b0 -- web/src/pages/org-edit/YamlEditorPanel.tsx | head -150Repository: Aureliolo/synthorg
Length of output: 5389
🏁 Script executed:
rg "useRef.*useEffect" web/src --type tsx -B 2 -A 8 | head -30Repository: Aureliolo/synthorg
Length of output: 89
🏁 Script executed:
rg "prevConfigRef|prevStateRef" web/src -A 5 | head -40Repository: Aureliolo/synthorg
Length of output: 1350
🏁 Script executed:
git show 60144f9:web/src/pages/org-edit/GeneralTab.tsx | head -80Repository: Aureliolo/synthorg
Length of output: 2798
Move config synchronization to useEffect to prevent stale state on render interruption.
Lines 17-25 mutate prevConfigRef.current during render, then schedule state updates. If React interrupts the render after the mutation but before state commits, the ref persists its new value and subsequent renders skip the sync block (because config === prevConfigRef.current is true), leaving the editor out of sync. Replace with a useEffect(() => { ... }, [config]) dependency array to ensure synchronization happens after render commits.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@web/src/pages/org-edit/YamlEditorPanel.tsx` around lines 17 - 25, The
render-time mutation of prevConfigRef should be moved into a useEffect to avoid
stale state when renders are interrupted: remove the in-render block that
compares and assigns prevConfigRef.current to config and instead add
useEffect(() => { if (config !== prevConfigRef.current) { prevConfigRef.current
= config; if (config && !dirty) { setYamlText(serializeToYaml(config));
setDirty(false); setParseError(null); } } }, [config, dirty]); so
synchronization runs after commit and uses serializeToYaml, setYamlText,
setDirty, and setParseError as before; keep prevConfigRef as a ref to track the
last synced config.
| const prevPresetRef = useRef<typeof preset | undefined>(undefined) | ||
| const prevSelectedPresetRef = useRef<typeof selectedPreset | undefined>(undefined) | ||
| const modeChanged = mode !== prevModeRef.current | ||
| const providerChanged = provider !== prevProviderRef.current | ||
| const presetChanged = preset !== prevPresetRef.current | ||
| const selectedPresetChanged = selectedPreset !== prevSelectedPresetRef.current |
There was a problem hiding this comment.
A preset refresh can wipe in-progress edits.
This guard treats any new preset object as a user selection change. Because the drawer refreshes presets on open, a later store update can replace the preset instances and re-enter this block even though selectedPreset never changed, which overwrites edited name / baseUrl / litellmProvider fields and clears any entered credentials.
🛠️ Suggested fix
- const presetChanged = preset !== prevPresetRef.current
+ const presetBecameAvailable = prevPresetRef.current == null && preset != null
const selectedPresetChanged = selectedPreset !== prevSelectedPresetRef.current
- if (presetChanged || selectedPresetChanged) {
+ if (selectedPresetChanged || presetBecameAvailable) {
if (selectedPreset === '__custom__') {
setName('')
setAuthType('api_key')
setApiKey('')Also applies to: 80-98
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@web/src/pages/providers/ProviderFormDrawer.tsx` around lines 63 - 68, The
guard is comparing preset objects by reference which can flip true when the
presets array is refreshed, wiping in-progress edits; change the comparisons to
use a stable unique key instead of object identity (e.g., compare
selectedPreset?.id or selectedPreset?.key and preset?.id) and store those keys
in prevPresetRef / prevSelectedPresetRef (or introduce prevPresetIdRef /
prevSelectedPresetIdRef) so that presetChanged and selectedPresetChanged reflect
real user selection changes rather than new object instances; update the logic
in the functions/variables named prevPresetRef, prevSelectedPresetRef,
presetChanged, and selectedPresetChanged (and the analogous guards later in the
file) to use the stable id comparison.
web/src/pages/setup/MiniOrgChart.tsx
Outdated
| return ( | ||
| <AgentNode | ||
| key={`${agent.name}-${agentIdx}`} | ||
| key={agent.name} |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, let's locate and examine the MiniOrgChart.tsx file
fd -type f -name "MiniOrgChart.tsx"Repository: Aureliolo/synthorg
Length of output: 232
🏁 Script executed:
# Once found, let's read the relevant section with context
head -n 200 web/src/pages/setup/MiniOrgChart.tsx | tail -n +150Repository: Aureliolo/synthorg
Length of output: 966
🏁 Script executed:
# Let me search for the Agent type definition and any uniqueness constraints
rg "agent\.name|agents.*map|Agent.*interface|Agent.*type" web/src/pages/setup/MiniOrgChart.tsx -B 2 -A 2Repository: Aureliolo/synthorg
Length of output: 825
🏁 Script executed:
# Also check the broader file structure to understand data flow
head -n 50 web/src/pages/setup/MiniOrgChart.tsxRepository: Aureliolo/synthorg
Length of output: 1088
🏁 Script executed:
# Look for Agent type definitions in the codebase
fd -name "*.ts" -o -name "*.tsx" | xargs rg "interface Agent|type Agent" -A 5 | head -n 100Repository: Aureliolo/synthorg
Length of output: 5833
🏁 Script executed:
# Find SetupAgentSummary definition
rg "SetupAgentSummary" web/src/api/types.ts -A 10Repository: Aureliolo/synthorg
Length of output: 687
🏁 Script executed:
# Let me also count the exact lines in the map callback to verify >8 line guideline
cat -n web/src/pages/setup/MiniOrgChart.tsx | sed -n '161,175p'Repository: Aureliolo/synthorg
Length of output: 675
Use a collision-safe key and extract the agent node map to a separate component.
Line 167 uses agent.name as the key, which collides when multiple agents in the same department share a name. Use ${agent.name}-${agentIdx} to ensure uniqueness.
Additionally, the map callback (lines 161–175) exceeds 8 lines of JSX. Extract the <AgentNode> rendering into a separate component for reusability and testability, per the guidelines for complex .map() expressions.
🔧 Proposed fix
- key={agent.name}
+ // eslint-disable-next-line `@eslint-react/no-array-index-key` -- setup agents can share display names
+ key={`${agent.name}-${agentIdx}`}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@web/src/pages/setup/MiniOrgChart.tsx` at line 167, The map callback in
MiniOrgChart uses a non-unique key (agent.name) and is too large; change the key
to a collision-safe value like `${agent.name}-${agentIdx}` and extract the JSX
inside the .map into a new small component (e.g., AgentNodeItem or
AgentNodeRenderer) that accepts the agent, agentIdx, department and any
handlers/props used in the map and returns the <AgentNode> markup; then replace
the inline callback with a call to that component and pass the new unique key.
Ensure the new component is typed/prop-validated consistently with MiniOrgChart
and exported/defined near the file bottom for testability and reuse.
- Fix infinite re-render loop: remove useMemo from usePolling return, depend on stable start/stop callbacks in useBudgetData - Fix ProviderFormDrawer: rehydrate edit form on reopen, track open state, use selectedPreset change (not preset object identity) for auto-fill - Reset delete dialog state when agent/department changes in edit drawers - Simplify InlineEdit: compare value against editValue directly instead of ref tracking - Use composite keys with index tiebreaker for ProseInsight, ToolBadges, AgentsStep, MiniOrgChart, SetupSummary (prevents duplicate React keys) - Update CLAUDE.md and getting_started.md lint comments to note zero-warning enforcement - Use npm --prefix in eslint-web pre-commit hook entry Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (1)
web/src/pages/providers/ProviderFormDrawer.tsx (1)
70-84:⚠️ Potential issue | 🔴 CriticalInclude
providerChangedin the edit-mode secret reset.This reset only runs on
openChangedormodeChanged, but the prefill right below also runs onproviderChanged. If the drawer stays open while the edited provider changes, the previousapiKey/subscriptionTokenremain in state and can be submitted for the new provider.🛠️ Minimal fix
- if (open && mode === 'edit' && (openChanged || modeChanged)) { + if (open && mode === 'edit' && (openChanged || modeChanged || providerChanged)) { setSelectedPreset(null) setApiKey('') setSubscriptionToken('') }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@web/src/pages/providers/ProviderFormDrawer.tsx` around lines 70 - 84, The credential-clear branch for the drawer only checks openChanged or modeChanged, so when the drawer remains open and provider changes the old secrets persist; update the condition used where setSelectedPreset, setApiKey, and setSubscriptionToken are cleared to also include providerChanged (same gating as the pre-fill block) so secrets are reset whenever open && mode === 'edit' and (openChanged || modeChanged || providerChanged).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@web/src/hooks/usePolling.ts`:
- Around line 87-89: In useApprovalsData.ts, stop using the mutable polling
object as an effect dependency (which causes restarts each render); change the
effect dependency array that currently uses [polling] to [] and add the
eslint-disable-line comment: "eslint-disable-line `@eslint-react/exhaustive-deps`
-- start/stop are stable useCallback refs" (same pattern used in
useDashboardData.ts/useTaskBoardData.ts/useProvidersData.ts/useAgentsData.ts) so
the effect relying on the stable start/stop refs from usePolling does not
unnecessarily restart.
In `@web/src/pages/providers/ProviderFormDrawer.tsx`:
- Around line 60-68: The current render-phase reads and writes refs
(prevProviderRef, prevModeRef, prevOpenRef, prevSelectedPresetRef) to compute
flags (modeChanged, providerChanged, openChanged, selectedPresetChanged), which
violates React's render purity; replace these refs with a state snapshot (e.g.,
a single useState holding {mode, open, provider, selectedPreset}) and move
change-detection and snapshot updates into a useEffect that runs after commit
(depend on [mode, open, provider, selectedPreset]) so you compute the *Changed
flags from the previous state and then call setPrev(...) inside the effect to
update the snapshot. Ensure all references to
modeChanged/providerChanged/openChanged/selectedPresetChanged derive from the
state snapshot rather than reading/writing ref.current during render.
---
Duplicate comments:
In `@web/src/pages/providers/ProviderFormDrawer.tsx`:
- Around line 70-84: The credential-clear branch for the drawer only checks
openChanged or modeChanged, so when the drawer remains open and provider changes
the old secrets persist; update the condition used where setSelectedPreset,
setApiKey, and setSubscriptionToken are cleared to also include providerChanged
(same gating as the pre-fill block) so secrets are reset whenever open && mode
=== 'edit' and (openChanged || modeChanged || providerChanged).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: ba16b460-c0d0-4457-b897-1ee490c3db30
📒 Files selected for processing (14)
.pre-commit-config.yamlCLAUDE.mddocs/getting_started.mdweb/src/components/ui/inline-edit.tsxweb/src/hooks/useBudgetData.tsweb/src/hooks/usePolling.tsweb/src/pages/agents/ProseInsight.tsxweb/src/pages/agents/ToolBadges.tsxweb/src/pages/org-edit/AgentEditDrawer.tsxweb/src/pages/org-edit/DepartmentEditDrawer.tsxweb/src/pages/providers/ProviderFormDrawer.tsxweb/src/pages/setup/AgentsStep.tsxweb/src/pages/setup/MiniOrgChart.tsxweb/src/pages/setup/SetupSummary.tsx
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
- GitHub Check: Build Backend
- GitHub Check: Build Web
- GitHub Check: Dashboard Test
- GitHub Check: Dependency Review
- GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (7)
**/*.md
📄 CodeRabbit inference engine (CLAUDE.md)
When a spec topic is referenced (e.g., 'the Agents page' or 'the Engine page's Crash Recovery section'), read the relevant
docs/design/page before coding. When approved deviations occur, update the relevantdocs/design/page to reflect the new reality.
Files:
docs/getting_started.mdCLAUDE.md
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx}: Always reuse existing components fromweb/src/components/ui/before creating new ones. Refer to the Web Dashboard Design System component inventory (StatusBadge, MetricCard, Sparkline, SectionCard, AgentCard, DeptHealthBar, ProgressGauge, StatPill, Avatar, Button, Toast, Skeleton variants, EmptyState, ErrorBoundary, ConfirmDialog, CommandPalette, InlineEdit, AnimatedPresence, StaggerGroup/Item, Drawer, InputField, SelectField, SliderField, ToggleField, TaskStatusIndicator, PriorityBadge, ProviderHealthBadge) for all page compositions.
Use design tokens exclusively for colors, typography, spacing, shadows, and borders. Never hardcode hex values, rgba colors, fontFamily, or pixel values for layout spacing in .tsx/.ts files. Use Tailwind semantic classes (text-foreground, bg-card, text-accent, text-success, bg-danger) or CSS variables (var(--so-*)).
Use Hypothesis equivalent fast-check for property-based testing in React/TypeScript:fc.assert+fc.property.
Files:
web/src/pages/agents/ProseInsight.tsxweb/src/hooks/usePolling.tsweb/src/hooks/useBudgetData.tsweb/src/pages/setup/MiniOrgChart.tsxweb/src/pages/setup/SetupSummary.tsxweb/src/pages/setup/AgentsStep.tsxweb/src/pages/agents/ToolBadges.tsxweb/src/pages/org-edit/DepartmentEditDrawer.tsxweb/src/pages/org-edit/AgentEditDrawer.tsxweb/src/components/ui/inline-edit.tsxweb/src/pages/providers/ProviderFormDrawer.tsx
web/src/**/*.tsx
📄 CodeRabbit inference engine (CLAUDE.md)
web/src/**/*.tsx: Do not recreate inline status indicators — use<StatusBadge>. Do not build card-with-header layouts from scratch — use<SectionCard>. Do not create metric displays with inlinetext-metric font-bold— use<MetricCard>. Do not render initials circles manually — use<Avatar>. Do not create complex (>8 line) JSX inside.map()— extract to a shared component.
Use design token CSS variables exclusively for all spacing (p-card, gap-section-gap, gap-grid-gap), shadows (var(--so-shadow-card-hover)), and borders (border-border, border-bright). Never hardcode pixel values or color values in .tsx files.
Files:
web/src/pages/agents/ProseInsight.tsxweb/src/pages/setup/MiniOrgChart.tsxweb/src/pages/setup/SetupSummary.tsxweb/src/pages/setup/AgentsStep.tsxweb/src/pages/agents/ToolBadges.tsxweb/src/pages/org-edit/DepartmentEditDrawer.tsxweb/src/pages/org-edit/AgentEditDrawer.tsxweb/src/components/ui/inline-edit.tsxweb/src/pages/providers/ProviderFormDrawer.tsx
web/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Extract complex JSX blocks (>8 lines) from
.map()into separate shared components rather than inline JSX. This ensures reusability and testability of rendered list items and card contents.
Files:
web/src/pages/agents/ProseInsight.tsxweb/src/hooks/usePolling.tsweb/src/hooks/useBudgetData.tsweb/src/pages/setup/MiniOrgChart.tsxweb/src/pages/setup/SetupSummary.tsxweb/src/pages/setup/AgentsStep.tsxweb/src/pages/agents/ToolBadges.tsxweb/src/pages/org-edit/DepartmentEditDrawer.tsxweb/src/pages/org-edit/AgentEditDrawer.tsxweb/src/components/ui/inline-edit.tsxweb/src/pages/providers/ProviderFormDrawer.tsx
web/**/*.tsx
📄 CodeRabbit inference engine (CLAUDE.md)
web/**/*.tsx: Mount<ToastContainer>once in the AppLayout component as the single toast notification manager for all pages. Use the Toast component for success/error/warning/info notifications with auto-dismiss queue.
Use<ErrorBoundary>with thelevelprop (page/section/component) to provide appropriate error isolation and recovery for different component hierarchies.
Files:
web/src/pages/agents/ProseInsight.tsxweb/src/pages/setup/MiniOrgChart.tsxweb/src/pages/setup/SetupSummary.tsxweb/src/pages/setup/AgentsStep.tsxweb/src/pages/agents/ToolBadges.tsxweb/src/pages/org-edit/DepartmentEditDrawer.tsxweb/src/pages/org-edit/AgentEditDrawer.tsxweb/src/components/ui/inline-edit.tsxweb/src/pages/providers/ProviderFormDrawer.tsx
web/src/pages/**/*.tsx
📄 CodeRabbit inference engine (CLAUDE.md)
Lazy-load page components via React Router. Page-scoped sub-components should be placed in
pages/<page-name>/subdirectories (e.g., pages/tasks/, pages/org-edit/) to keep the component tree organized.
Files:
web/src/pages/agents/ProseInsight.tsxweb/src/pages/setup/MiniOrgChart.tsxweb/src/pages/setup/SetupSummary.tsxweb/src/pages/setup/AgentsStep.tsxweb/src/pages/agents/ToolBadges.tsxweb/src/pages/org-edit/DepartmentEditDrawer.tsxweb/src/pages/org-edit/AgentEditDrawer.tsxweb/src/pages/providers/ProviderFormDrawer.tsx
web/src/components/ui/**/*.tsx
📄 CodeRabbit inference engine (CLAUDE.md)
web/src/components/ui/**/*.tsx: Every new shared component inweb/src/components/ui/must have a corresponding.stories.tsxStorybook file documenting all states (default, hover, loading, error, empty) alongside the component file.
Export component props as a TypeScript interface. Use design tokens exclusively — no hardcoded colors, fonts, or spacing. Importcnfrom@/lib/utilsfor conditional class merging.
Files:
web/src/components/ui/inline-edit.tsx
🧠 Learnings (30)
📓 Common learnings
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T12:42:32.168Z
Learning: Applies to web/src/**/*.tsx : Do not recreate inline status indicators — use `<StatusBadge>`. Do not build card-with-header layouts from scratch — use `<SectionCard>`. Do not create metric displays with inline `text-metric font-bold` — use `<MetricCard>`. Do not render initials circles manually — use `<Avatar>`. Do not create complex (>8 line) JSX inside `.map()` — extract to a shared component.
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T12:42:32.168Z
Learning: Applies to web/src/**/*.{ts,tsx} : Extract complex JSX blocks (>8 lines) from `.map()` into separate shared components rather than inline JSX. This ensures reusability and testability of rendered list items and card contents.
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T12:42:32.168Z
Learning: Applies to web/package.json : Require Node.js 22+, TypeScript 6.0+. Core dependencies: React 19, react-router, shadcn/ui, Radix UI, Tailwind CSS 4, Zustand, tanstack/react-query, xyflow/react, dagrejs/dagre, dnd-kit, Recharts, Framer Motion, cmdk, Axios, Lucide React, fontsource-variable/geist, fontsource-variable/geist-mono. Dev/test: Storybook 10, Vitest, fast-check, ESLint, eslint-react/eslint-plugin, eslint-plugin-security.
📚 Learning: 2026-03-14T15:43:05.601Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-14T15:43:05.601Z
Learning: Applies to web/package.json : Web dashboard Node.js 20+; dependencies in web/package.json (Vue 3, PrimeVue, Tailwind CSS, Pinia, VueFlow, ECharts, Axios, vue-draggable-plus, Vitest, ESLint, vue-tsc)
Applied to files:
docs/getting_started.mdCLAUDE.md.pre-commit-config.yaml
📚 Learning: 2026-03-15T18:17:43.675Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Applies to web/** : Web dashboard: Node.js 20+, dependencies in web/package.json (Vue 3, PrimeVue, Tailwind CSS, Pinia, VueFlow, ECharts, Axios, vue-draggable-plus, Vitest, fast-check, ESLint, vue-tsc).
Applied to files:
docs/getting_started.mdCLAUDE.md
📚 Learning: 2026-03-28T12:42:32.168Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T12:42:32.168Z
Learning: Applies to web/package.json : Require Node.js 22+, TypeScript 6.0+. Core dependencies: React 19, react-router, shadcn/ui, Radix UI, Tailwind CSS 4, Zustand, tanstack/react-query, xyflow/react, dagrejs/dagre, dnd-kit, Recharts, Framer Motion, cmdk, Axios, Lucide React, fontsource-variable/geist, fontsource-variable/geist-mono. Dev/test: Storybook 10, Vitest, fast-check, ESLint, eslint-react/eslint-plugin, eslint-plugin-security.
Applied to files:
docs/getting_started.mdweb/src/pages/org-edit/DepartmentEditDrawer.tsxCLAUDE.mdweb/src/pages/org-edit/AgentEditDrawer.tsxweb/src/pages/providers/ProviderFormDrawer.tsx
📚 Learning: 2026-03-28T12:42:32.168Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T12:42:32.168Z
Learning: Applies to web/tsconfig.json : TypeScript 6.0+: Remove deprecated `baseUrl` (use `paths` relative to tsconfig directory). Remove explicit `esModuleInterop: true` (now default, non-editable). Set `types: []` and explicitly list needed types (e.g., `vitest/globals`). Use `DOM` lib (no separate `DOM.Iterable`). Use `moduleResolution: bundler` or `nodenext` (no `classic` or `node10`). `strict: true` is default. `noUncheckedSideEffectImports: true` is default (CSS imports need type declarations via `/// <reference types="vite/client" />`).
Applied to files:
docs/getting_started.mdCLAUDE.md
📚 Learning: 2026-03-20T08:28:32.845Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-20T08:28:32.845Z
Learning: Applies to web/src/__tests__/**/*.{ts,js} : Dashboard testing: Vitest unit tests organized by feature under `web/src/__tests__/`. Use fast-check for property-based testing (`fc.assert` + `fc.property`).
Applied to files:
docs/getting_started.mdCLAUDE.md
📚 Learning: 2026-03-15T18:17:43.675Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Applies to docker/{Dockerfile*,compose.yml} : Docker: Backend uses 3-stage build (builder → setup → distroless runtime), Chainguard Python, non-root (UID 65532), CIS-hardened. Web uses nginxinc/nginx-unprivileged, Vue 3 SPA with PrimeVue + Tailwind CSS, SPA routing, API/WebSocket proxy to backend.
Applied to files:
docs/getting_started.mdCLAUDE.md
📚 Learning: 2026-03-19T11:33:01.580Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:33:01.580Z
Learning: Applies to docker/Dockerfile.web : `nginxinc/nginx-unprivileged` base with non-root user (UID 101), Vue 3 SPA (PrimeVue + Tailwind CSS), SPA routing, API/WebSocket proxy to backend
Applied to files:
docs/getting_started.mdCLAUDE.md
📚 Learning: 2026-03-28T12:42:32.168Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T12:42:32.168Z
Learning: Applies to web/src/**/*.{ts,tsx} : Extract complex JSX blocks (>8 lines) from `.map()` into separate shared components rather than inline JSX. This ensures reusability and testability of rendered list items and card contents.
Applied to files:
web/src/pages/agents/ProseInsight.tsxweb/src/pages/setup/MiniOrgChart.tsxweb/src/pages/setup/AgentsStep.tsxweb/src/pages/agents/ToolBadges.tsxweb/src/components/ui/inline-edit.tsx
📚 Learning: 2026-03-28T12:42:32.168Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T12:42:32.168Z
Learning: Applies to web/src/**/*.tsx : Do not recreate inline status indicators — use `<StatusBadge>`. Do not build card-with-header layouts from scratch — use `<SectionCard>`. Do not create metric displays with inline `text-metric font-bold` — use `<MetricCard>`. Do not render initials circles manually — use `<Avatar>`. Do not create complex (>8 line) JSX inside `.map()` — extract to a shared component.
Applied to files:
web/src/pages/agents/ProseInsight.tsxweb/src/pages/setup/MiniOrgChart.tsxweb/src/pages/setup/SetupSummary.tsxweb/src/pages/setup/AgentsStep.tsxweb/src/pages/agents/ToolBadges.tsxweb/src/pages/org-edit/AgentEditDrawer.tsxweb/src/components/ui/inline-edit.tsx
📚 Learning: 2026-03-28T12:42:32.168Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T12:42:32.168Z
Learning: Applies to **/*.{ts,tsx} : Always reuse existing components from `web/src/components/ui/` before creating new ones. Refer to the Web Dashboard Design System component inventory (StatusBadge, MetricCard, Sparkline, SectionCard, AgentCard, DeptHealthBar, ProgressGauge, StatPill, Avatar, Button, Toast, Skeleton variants, EmptyState, ErrorBoundary, ConfirmDialog, CommandPalette, InlineEdit, AnimatedPresence, StaggerGroup/Item, Drawer, InputField, SelectField, SliderField, ToggleField, TaskStatusIndicator, PriorityBadge, ProviderHealthBadge) for all page compositions.
Applied to files:
web/src/pages/setup/MiniOrgChart.tsxweb/src/pages/agents/ToolBadges.tsxweb/src/pages/org-edit/DepartmentEditDrawer.tsxweb/src/pages/org-edit/AgentEditDrawer.tsx
📚 Learning: 2026-03-15T21:20:09.993Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:20:09.993Z
Learning: Applies to web/src/components/** : Vue components organized by feature (agents/, approvals/, budget/, common/, dashboard/, layout/, messages/, org-chart/, tasks/).
Applied to files:
web/src/pages/setup/MiniOrgChart.tsx
📚 Learning: 2026-03-28T12:42:32.168Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T12:42:32.168Z
Learning: Applies to web/src/pages/**/*.tsx : Lazy-load page components via React Router. Page-scoped sub-components should be placed in `pages/<page-name>/` subdirectories (e.g., pages/tasks/, pages/org-edit/) to keep the component tree organized.
Applied to files:
web/src/pages/org-edit/DepartmentEditDrawer.tsx
📚 Learning: 2026-03-28T12:42:32.168Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T12:42:32.168Z
Learning: Applies to .storybook/**/*.{ts,tsx} : Storybook 10 (ESM-only): Use `defineMain` from `storybook/react-vite/node` (main.ts) and `definePreview` from `storybook/react-vite` (preview.tsx). Essentials (backgrounds, controls, viewport, actions, toolbars, measure, outline) are built-in; if using `tags: ['autodocs']` or MDX, install `storybook/addon-docs`. Import from `storybook/test` (not `storybook/test`), `storybook/actions` (not `storybook/addon-actions`). Use `parameters.backgrounds.options` (object keyed by name) + `initialGlobals.backgrounds.value`. Set `parameters.a11y.test: 'error' | 'todo' | 'off'` globally to enforce WCAG compliance.
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-28T12:42:32.168Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T12:42:32.168Z
Learning: Applies to web/src/**/*.stories.tsx : Every shared component in `web/src/components/ui/` must have a `.stories.tsx` file documenting all states (default, hover, loading, error, empty, disabled variants). Mount `ToastContainer` in Storybook wrapper if testing toast integration. Use type-safe Storybook 10 config.
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-15T18:17:43.675Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Pre-commit hooks: trailing-whitespace, end-of-file-fixer, check-yaml, check-toml, check-json, check-merge-conflict, check-added-large-files, no-commit-to-branch (main), ruff check+format, gitleaks, hadolint (Dockerfile linting).
Applied to files:
CLAUDE.md.pre-commit-config.yaml
📚 Learning: 2026-03-15T12:00:18.113Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T12:00:18.113Z
Learning: Commits: <type>: <description> — types: feat, fix, refactor, docs, test, chore, perf, ci. Enforced by commitizen (commit-msg hook). Signed commits: required on main via branch protection — all commits must be GPG/SSH signed.
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-15T18:17:43.675Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Pre-push hooks: mypy type-check + pytest unit tests + golangci-lint + go vet + go test (CLI, conditional on cli/**/*.go) (fast gate before push, skipped in pre-commit.ci — dedicated CI jobs already run these).
Applied to files:
CLAUDE.md.pre-commit-config.yaml
📚 Learning: 2026-03-28T12:42:32.168Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T12:42:32.168Z
Learning: Use commit type prefixes: `feat:`, `fix:`, `refactor:`, `docs:`, `test:`, `chore:`, `perf:`, `ci:`. Pre-1.0 version bumping: `fix:`/`feat:` = patch, `feat!:`/`BREAKING CHANGE` = minor. Signed commits required on main via branch protection.
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-19T11:19:40.044Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:19:40.044Z
Learning: CLI workflow (`.github/workflows/cli.yml`) runs Go lint (golangci-lint + go vet) + test (race, coverage) + build (cross-compile matrix) + vulnerability check (govulncheck) + fuzz testing. Cross-compiles for linux/darwin/windows × amd64/arm64. GoReleaser release on v* tags with cosign keyless signing and SLSA L3 attestations.
Applied to files:
CLAUDE.md.pre-commit-config.yaml
📚 Learning: 2026-03-15T21:32:02.880Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to .github/workflows/cli.yml : CLI workflow: Go lint (golangci-lint + go vet) + test (-race -coverprofile) + build (cross-compile: linux/darwin/windows × amd64/arm64) + govulncheck + fuzz testing (main-only, 30s/target, continue-on-error, matrix over 4 packages). cli-pass gate includes fuzz as informational. GoReleaser release on v* tags. Cosign keyless signing of checksums.txt. SLSA L3 provenance attestations. Sigstore bundle (.sigstore.json) attached. Post-release appends checksums/verification/provenance to draft release notes.
Applied to files:
CLAUDE.md.pre-commit-config.yaml
📚 Learning: 2026-03-21T14:12:17.848Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-21T14:12:17.848Z
Learning: CLI workflow (`cli.yml`): Go lint/test/build (cross-compile) + govulncheck + fuzz. GoReleaser release on `v*` tags with cosign signing + SLSA provenance
Applied to files:
CLAUDE.md.pre-commit-config.yaml
📚 Learning: 2026-03-15T21:32:02.880Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to .github/workflows/docker.yml : Docker workflow: builds backend + web + sandbox images, pushes to GHCR, signs with cosign. SLSA L3 provenance attestations via actions/attest-build-provenance. Scans: Trivy (CRITICAL = hard fail, HIGH = warn) + Grype (critical cutoff) + CIS Docker Benchmark v1.6.0 compliance (informational). CVE triage via .github/.trivyignore.yaml and .github/.grype.yaml. Images only pushed after scans pass. Triggers on push to main and version tags (v*).
Applied to files:
CLAUDE.md.pre-commit-config.yaml
📚 Learning: 2026-03-20T12:59:09.553Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-20T12:59:09.553Z
Learning: NEVER create a PR directly — `gh pr create` is blocked by hookify. ALWAYS use `/pre-pr-review` to create PRs — it runs automated checks + review agents + fixes before creating the PR. For trivial/docs-only changes: `/pre-pr-review quick` skips agents but still runs automated checks.
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-28T12:42:32.168Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T12:42:32.168Z
Learning: Applies to .github/workflows/**/*.yml : Use `dorny/paths-filter` for path-based job filtering — jobs only run when their domain is affected. CLI has its own workflow (cli.yml). Coverage minimum: 80% (enforced in CI). All pre-commit hooks and pre-push checks run in CI but pre-push hooks are skipped in pre-commit.ci.
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-28T12:42:32.168Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T12:42:32.168Z
Learning: Applies to web/src/stores/**/*.ts : Use Zustand stores for global state management: auth, WebSocket, toast, analytics, setup wizard, company, agents, budget, tasks, settings, providers, and per-domain stores for each page.
Applied to files:
web/src/pages/org-edit/AgentEditDrawer.tsx
📚 Learning: 2026-03-21T11:08:01.542Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-21T11:08:01.542Z
Learning: NEVER use `cd` in Bash commands — the working directory is already set to the project root. Use absolute paths or run commands directly.
Applied to files:
.pre-commit-config.yaml
📚 Learning: 2026-03-16T19:52:03.656Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-16T19:52:03.656Z
Learning: Applies to cli/**/*.go : Lint CLI Go code with golangci-lint and go vet; test with go test -race; check vulnerabilities with govulncheck
Applied to files:
.pre-commit-config.yaml
📚 Learning: 2026-03-19T11:30:29.217Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:30:29.217Z
Learning: Applies to cli/**/*.go : Run Go lint via `golangci-lint run`, vet via `go vet`, tests via `go test ./...`, and fuzz via `go test -fuzz=FuzzTarget -fuzztime=30s`
Applied to files:
.pre-commit-config.yaml
📚 Learning: 2026-03-21T14:12:17.848Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-21T14:12:17.848Z
Learning: Docker workflow (`docker.yml`): build + Trivy/Grype scan + push to GHCR + cosign sign + SLSA L3 provenance. CVE triage: `.github/.trivyignore.yaml`, `.github/.grype.yaml`
Applied to files:
.pre-commit-config.yaml
🔇 Additional comments (14)
web/src/pages/setup/MiniOrgChart.tsx (1)
167-168: LGTM — ESLint suppression is appropriate here.The
eslint-disablecomment is justified:SetupAgentSummaryhas no unique identifier (confirmed by the type definition showing onlyname: string), and agents within a department can share display names. The composite key${agent.name}-${agentIdx}correctly combines the semantic identifier with an index tiebreaker, which aligns with the PR's stated approach for lists lacking natural unique IDs.The past review concern about collision-safe keys has been addressed.
web/src/components/ui/inline-edit.tsx (1)
44-46: LGTM! Correctly implements the React-recommended pattern for prop-to-state sync.This replaces the unsafe render-phase
ref.currentmutation flagged in the prior review with React's documented "adjusting state when a prop changes" pattern. The guard condition (state === 'display' && value !== editValue) prevents infinite loops, and React will immediately retry rendering with the updated state without committing the stale render.web/src/pages/org-edit/AgentEditDrawer.tsx (1)
47-62: Clean implementation of the render-time state sync pattern.The
useRef+ conditional pattern correctly replacesuseEffectfor prop-to-state synchronization:
- Guards form initialization with
if (agent)to handle null case- Unconditionally resets
deleteOpenanddeletingon anyagentchange, properly clearing dialog state when drawer closes or switches agentsThis avoids ESLint's
set-state-in-effectwarnings while maintaining correct behavior.web/src/pages/org-edit/DepartmentEditDrawer.tsx (1)
36-46: Past review concern addressed — delete dialog state now resets correctly.The reset block now includes
setDeleteOpen(false)andsetDeleting(false)(lines 44-45), placed outside theif (department)guard. This ensures:
- Dialog state clears when switching between departments
- Dialog state clears when drawer closes (
department→null)- Form fields only initialize when a valid department is provided
Implementation is consistent with
AgentEditDrawer.tsxand correctly addresses the state leakage concern from prior review.web/src/pages/agents/ProseInsight.tsx (1)
21-26: LGTM!The composite key
${insight}-${index}correctly handles potential duplicate insight strings while maintaining stable React reconciliation. The ESLint disable comment is appropriately justified.web/src/pages/setup/SetupSummary.tsx (1)
98-101: LGTM!The composite key pattern and extracted
SetupAgentRowcomponent align with both the PR's key-uniqueness goals and the coding guidelines for extracting complex JSX from.map()calls.web/src/pages/setup/AgentsStep.tsx (1)
115-128: LGTM!The composite key
${agent.name}-${index}properly addresses the duplicate key concern when users edit agent names viahandleNameChange. The index tiebreaker ensures uniqueness while the name prefix provides meaningful identity for React reconciliation.web/src/pages/agents/ToolBadges.tsx (1)
31-34: LGTM!The ESLint disable comment appropriately documents why the index tiebreaker is needed for tools that may have duplicate names. The
ToolBadgecomponent is correctly extracted per coding guidelines..pre-commit-config.yaml (1)
106-112: LGTM!The
eslint-webhook is well-configured: usesnpm --prefix(addressing the past review), correctly scopes toweb/src/**/*.ts?(x)files, and runs on both pre-commit and pre-push stages. Adding it toci.skipis appropriate since CI has its own lint job.docs/getting_started.md (1)
140-140: LGTM!Documentation accurately reflects the new zero-warnings enforcement added to the lint script.
web/src/hooks/useBudgetData.ts (1)
63-67: LGTM!The dependency array correctly uses
polling.startandpolling.stop(stableuseCallbackrefs) rather than thepollingobject itself, which addresses the infinite re-render loop concern from the past review. The ESLint disable comment is appropriately justified.CLAUDE.md (2)
53-53: Accurate lint command documentation update.The “zero warnings enforced” note is clear and aligned with the new lint gate behavior.
351-352: Hook pipeline docs are consistent with the ESLint enforcement goal.Including
eslint-webin both pre-commit and pre-push sections makes the guardrails explicit and actionable.web/src/pages/providers/ProviderFormDrawer.tsx (1)
86-105: Good change: preset refreshes no longer clobber draft edits.Keying this branch off
selectedPresetChangedavoids re-entering the autofill path just because the presets store recreated the preset objects.
| // start/stop are stable useCallback refs; return a plain object so consumers | ||
| // depend on the individual refs, not an object whose identity changes on every state update. | ||
| return { active, error, start, stop } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Description: Find all usePolling consumers and check their effect dependency patterns.
# Expected: All should use [polling.start, polling.stop] or [] with eslint-disable, not [polling].
echo "=== usePolling consumers ==="
rg -n "usePolling\(" --type=ts --type=tsx -g '!usePolling.ts' web/src/
echo ""
echo "=== Checking for problematic [polling] dependency pattern ==="
rg -nA5 "usePolling\(" --type=ts -g '!usePolling.ts' web/src/ | rg -A3 "useEffect"Repository: Aureliolo/synthorg
Length of output: 3132
🏁 Script executed:
# Check useApprovalsData.ts dependency pattern
cat -n web/src/hooks/useApprovalsData.ts | sed -n '70,80p'Repository: Aureliolo/synthorg
Length of output: 391
🏁 Script executed:
# Check useAgentDetailData.ts dependency pattern
cat -n web/src/hooks/useAgentDetailData.ts | sed -n '80,90p'Repository: Aureliolo/synthorg
Length of output: 502
🏁 Script executed:
# Check useProviderDetailData.ts dependency pattern
cat -n web/src/hooks/useProviderDetailData.ts | sed -n '50,60p'Repository: Aureliolo/synthorg
Length of output: 428
🏁 Script executed:
# Check useDashboardData.ts dependency pattern
cat -n web/src/hooks/useDashboardData.ts | sed -n '49,58p'Repository: Aureliolo/synthorg
Length of output: 459
🏁 Script executed:
# Check useTaskBoardData.ts dependency pattern
cat -n web/src/hooks/useTaskBoardData.ts | sed -n '60,70p'Repository: Aureliolo/synthorg
Length of output: 434
🏁 Script executed:
# Check useProvidersData.ts dependency pattern
cat -n web/src/hooks/useProvidersData.ts | sed -n '30,40p'Repository: Aureliolo/synthorg
Length of output: 447
🏁 Script executed:
# Check useAgentsData.ts dependency pattern
cat -n web/src/hooks/useAgentsData.ts | sed -n '40,50p'Repository: Aureliolo/synthorg
Length of output: 530
Fix useApprovalsData.ts to prevent unnecessary polling restarts on every render.
The plain object return from usePolling is correct, but useApprovalsData.ts (lines 74–77) uses [polling] as an effect dependency, which will trigger restarts on every render since the object identity changes constantly.
Change the dependency array to [] with an eslint-disable comment (matching the pattern used in useDashboardData.ts, useTaskBoardData.ts, useProvidersData.ts, and useAgentsData.ts):
}, []) // eslint-disable-line `@eslint-react/exhaustive-deps` -- start/stop are stable useCallback refs
All other usePolling consumers already follow the correct pattern.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@web/src/hooks/usePolling.ts` around lines 87 - 89, In useApprovalsData.ts,
stop using the mutable polling object as an effect dependency (which causes
restarts each render); change the effect dependency array that currently uses
[polling] to [] and add the eslint-disable-line comment: "eslint-disable-line
`@eslint-react/exhaustive-deps` -- start/stop are stable useCallback refs" (same
pattern used in
useDashboardData.ts/useTaskBoardData.ts/useProvidersData.ts/useAgentsData.ts) so
the effect relying on the stable start/stop refs from usePolling does not
unnecessarily restart.
| // Render-phase state sync: capture previous values before comparisons | ||
| const prevProviderRef = useRef<typeof provider | undefined>(undefined) | ||
| const prevModeRef = useRef<typeof mode | undefined>(undefined) | ||
| const prevOpenRef = useRef<typeof open | undefined>(undefined) | ||
| const prevSelectedPresetRef = useRef<typeof selectedPreset | undefined>(undefined) | ||
| const modeChanged = mode !== prevModeRef.current | ||
| const providerChanged = provider !== prevProviderRef.current | ||
| const openChanged = open !== prevOpenRef.current | ||
| const selectedPresetChanged = selectedPreset !== prevSelectedPresetRef.current |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, let's look at the ProviderFormDrawer.tsx file to see the flagged code
cat -n web/src/pages/providers/ProviderFormDrawer.tsx | head -150Repository: Aureliolo/synthorg
Length of output: 6270
🏁 Script executed:
# Get file size to understand scope
wc -l web/src/pages/providers/ProviderFormDrawer.tsxRepository: Aureliolo/synthorg
Length of output: 112
🌐 Web query:
react.dev useRef render phase state mutation warning documentation
💡 Result:
The official React documentation on react.dev explicitly warns against mutating or reading useRef's .current during the render phase, except for lazy initialization. Key points from the docs: - Do not write or read ref.current during rendering, except for initialization. This makes your component's behavior unpredictable because React expects the component body to be a pure function. - Reading/writing refs during render breaks purity assumptions, leading to issues in Strict Mode, concurrent features, and React Compiler optimizations. - Use refs in event handlers, effects, or for lazy init (e.g., if (ref.current === null) ref.current = computeValue;). - ESLint rule in eslint-plugin-react-hooks ("refs") enforces this: flags reading/writing ref.current in render. - Strict Mode double-renders to detect such impurities; behavior may differ from production. There is no runtime console warning implemented yet (PR #18545 from 2020 discusses it but not merged), but docs, ESLint, and React Compiler provide static warnings. Mutating state-like values via ref during render mimics invalid state mutation patterns. Examples: Invalid (during render): function Bad({ value }) { const ref = useRef; ref.current = value; // ❌ Mutation warning return
Citations:
- 1: https://react.dev/reference/react/useRef
- 2: https://react.dev/reference/eslint-plugin-react-hooks/lints/refs
- 3: https://react.dev/reference/eslint-plugin-react-hooks
🏁 Script executed:
# Get lines 60-150 to understand the full render-phase logic pattern
sed -n '60,150p' web/src/pages/providers/ProviderFormDrawer.tsxRepository: Aureliolo/synthorg
Length of output: 3070
Use state instead of refs to track previous values.
React explicitly prohibits reading or writing ref.current during render. This code reads refs (lines 65–68) to compute *Changed flags, then writes to those same refs (lines 107–111) before the component returns—both violations of the documented pattern. Reading/writing refs during render breaks React's purity assumption and causes unpredictable behavior in Strict Mode and with concurrent rendering.
Instead, use useState for the previous-value snapshot and a useEffect to update those values after commit:
const [prev, setPrev] = useState({ mode, open, provider, selectedPreset })
useEffect(() => {
// Your change-detection logic here
setPrev({ mode, open, provider, selectedPreset })
}, [mode, open, provider, selectedPreset])This ensures change detection runs after React's commit phase, maintaining purity in render.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@web/src/pages/providers/ProviderFormDrawer.tsx` around lines 60 - 68, The
current render-phase reads and writes refs (prevProviderRef, prevModeRef,
prevOpenRef, prevSelectedPresetRef) to compute flags (modeChanged,
providerChanged, openChanged, selectedPresetChanged), which violates React's
render purity; replace these refs with a state snapshot (e.g., a single useState
holding {mode, open, provider, selectedPreset}) and move change-detection and
snapshot updates into a useEffect that runs after commit (depend on [mode, open,
provider, selectedPreset]) so you compute the *Changed flags from the previous
state and then call setPrev(...) inside the effect to update the snapshot.
Ensure all references to
modeChanged/providerChanged/openChanged/selectedPresetChanged derive from the
state snapshot rather than reading/writing ref.current during render.
…ta, credential clear on provider change - Fix useApprovalsData: depend on stable polling.start/stop refs instead of polling object (same infinite loop fix as useBudgetData) - Fix ProviderFormDrawer: include providerChanged in credential-clear guard so old apiKey/subscriptionToken don't persist when editing a different provider without closing the drawer Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
♻️ Duplicate comments (1)
web/src/pages/providers/ProviderFormDrawer.tsx (1)
60-111:⚠️ Potential issue | 🔴 CriticalUse a committed snapshot instead of render-mutated refs.
These
prev*.currentreads/writes happen during render, so they track the last attempted render, not the last committed one. Under concurrent/Strict Mode rendering, that can suppress the edit/create sync branches here and leave stale provider state or credentials in the form. Keep the render-phase sync if you want to avoidset-state-in-effect, but store the previous snapshot in component state and compare a stable provider key such asprovider?.nameinstead of the whole object.🛠️ Sketch
- const prevProviderRef = useRef<typeof provider | undefined>(undefined) - const prevModeRef = useRef<typeof mode | undefined>(undefined) - const prevOpenRef = useRef<typeof open | undefined>(undefined) - const prevSelectedPresetRef = useRef<typeof selectedPreset | undefined>(undefined) - const modeChanged = mode !== prevModeRef.current - const providerChanged = provider !== prevProviderRef.current - const openChanged = open !== prevOpenRef.current - const selectedPresetChanged = selectedPreset !== prevSelectedPresetRef.current + const providerKey = provider?.name ?? null + const [prevSync, setPrevSync] = useState(() => ({ + mode, + open, + providerKey, + selectedPreset, + })) + const modeChanged = mode !== prevSync.mode + const providerChanged = providerKey !== prevSync.providerKey + const openChanged = open !== prevSync.open + const selectedPresetChanged = selectedPreset !== prevSync.selectedPreset // existing guarded sync branches... - prevModeRef.current = mode - prevProviderRef.current = provider - prevOpenRef.current = open - prevSelectedPresetRef.current = selectedPreset + if (modeChanged || providerChanged || openChanged || selectedPresetChanged) { + setPrevSync({ mode, open, providerKey, selectedPreset }) + }React 19 docs: can a component read or write useRef.current during render, and what pattern does React recommend for storing information from previous renders instead?Also applies to: 139-140
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@web/src/pages/providers/ProviderFormDrawer.tsx` around lines 60 - 111, The render reads/writes prevModeRef/prevProviderRef/prevOpenRef/prevSelectedPresetRef during render which can be incorrect under concurrent rendering; instead create a committed snapshot in component state (e.g., prevSnapshot with keys mode, open, providerName = provider?.name, selectedPreset) and move the comparison-and-sync logic into a useEffect that depends on [mode, open, provider?.name, selectedPreset]; perform the same branch actions (clearing credentials, pre-filling fields, handling '__custom__' vs preset) inside that effect, and update prevSnapshot at the end of that effect—remove the render-phase updates to prevModeRef/prevProviderRef/prevOpenRef/prevSelectedPresetRef and compare stable providerName rather than the whole provider object.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In `@web/src/pages/providers/ProviderFormDrawer.tsx`:
- Around line 60-111: The render reads/writes
prevModeRef/prevProviderRef/prevOpenRef/prevSelectedPresetRef during render
which can be incorrect under concurrent rendering; instead create a committed
snapshot in component state (e.g., prevSnapshot with keys mode, open,
providerName = provider?.name, selectedPreset) and move the comparison-and-sync
logic into a useEffect that depends on [mode, open, provider?.name,
selectedPreset]; perform the same branch actions (clearing credentials,
pre-filling fields, handling '__custom__' vs preset) inside that effect, and
update prevSnapshot at the end of that effect—remove the render-phase updates to
prevModeRef/prevProviderRef/prevOpenRef/prevSelectedPresetRef and compare stable
providerName rather than the whole provider object.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 3b844227-ee20-4e90-aef8-ca3f49a42b2b
📒 Files selected for processing (2)
web/src/hooks/useApprovalsData.tsweb/src/pages/providers/ProviderFormDrawer.tsx
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
- GitHub Check: Build Web
- GitHub Check: Build Sandbox
- GitHub Check: Build Backend
- GitHub Check: Dashboard Test
- GitHub Check: Dependency Review
- GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx}: Always reuse existing components fromweb/src/components/ui/before creating new ones. Refer to the Web Dashboard Design System component inventory (StatusBadge, MetricCard, Sparkline, SectionCard, AgentCard, DeptHealthBar, ProgressGauge, StatPill, Avatar, Button, Toast, Skeleton variants, EmptyState, ErrorBoundary, ConfirmDialog, CommandPalette, InlineEdit, AnimatedPresence, StaggerGroup/Item, Drawer, InputField, SelectField, SliderField, ToggleField, TaskStatusIndicator, PriorityBadge, ProviderHealthBadge) for all page compositions.
Use design tokens exclusively for colors, typography, spacing, shadows, and borders. Never hardcode hex values, rgba colors, fontFamily, or pixel values for layout spacing in .tsx/.ts files. Use Tailwind semantic classes (text-foreground, bg-card, text-accent, text-success, bg-danger) or CSS variables (var(--so-*)).
Use Hypothesis equivalent fast-check for property-based testing in React/TypeScript:fc.assert+fc.property.
Files:
web/src/hooks/useApprovalsData.tsweb/src/pages/providers/ProviderFormDrawer.tsx
web/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Extract complex JSX blocks (>8 lines) from
.map()into separate shared components rather than inline JSX. This ensures reusability and testability of rendered list items and card contents.
Files:
web/src/hooks/useApprovalsData.tsweb/src/pages/providers/ProviderFormDrawer.tsx
web/src/**/*.tsx
📄 CodeRabbit inference engine (CLAUDE.md)
web/src/**/*.tsx: Do not recreate inline status indicators — use<StatusBadge>. Do not build card-with-header layouts from scratch — use<SectionCard>. Do not create metric displays with inlinetext-metric font-bold— use<MetricCard>. Do not render initials circles manually — use<Avatar>. Do not create complex (>8 line) JSX inside.map()— extract to a shared component.
Use design token CSS variables exclusively for all spacing (p-card, gap-section-gap, gap-grid-gap), shadows (var(--so-shadow-card-hover)), and borders (border-border, border-bright). Never hardcode pixel values or color values in .tsx files.
Files:
web/src/pages/providers/ProviderFormDrawer.tsx
web/**/*.tsx
📄 CodeRabbit inference engine (CLAUDE.md)
web/**/*.tsx: Mount<ToastContainer>once in the AppLayout component as the single toast notification manager for all pages. Use the Toast component for success/error/warning/info notifications with auto-dismiss queue.
Use<ErrorBoundary>with thelevelprop (page/section/component) to provide appropriate error isolation and recovery for different component hierarchies.
Files:
web/src/pages/providers/ProviderFormDrawer.tsx
web/src/pages/**/*.tsx
📄 CodeRabbit inference engine (CLAUDE.md)
Lazy-load page components via React Router. Page-scoped sub-components should be placed in
pages/<page-name>/subdirectories (e.g., pages/tasks/, pages/org-edit/) to keep the component tree organized.
Files:
web/src/pages/providers/ProviderFormDrawer.tsx
🧠 Learnings (4)
📓 Common learnings
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T12:00:18.113Z
Learning: Commits: <type>: <description> — types: feat, fix, refactor, docs, test, chore, perf, ci. Enforced by commitizen (commit-msg hook). Signed commits: required on main via branch protection — all commits must be GPG/SSH signed.
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-14T15:43:05.601Z
Learning: Applies to web/package.json : Web dashboard Node.js 20+; dependencies in web/package.json (Vue 3, PrimeVue, Tailwind CSS, Pinia, VueFlow, ECharts, Axios, vue-draggable-plus, Vitest, ESLint, vue-tsc)
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Pre-commit hooks: trailing-whitespace, end-of-file-fixer, check-yaml, check-toml, check-json, check-merge-conflict, check-added-large-files, no-commit-to-branch (main), ruff check+format, gitleaks, hadolint (Dockerfile linting).
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T12:42:32.168Z
Learning: Applies to web/src/**/*.{ts,tsx} : Extract complex JSX blocks (>8 lines) from `.map()` into separate shared components rather than inline JSX. This ensures reusability and testability of rendered list items and card contents.
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Pre-push hooks: mypy type-check + pytest unit tests + golangci-lint + go vet + go test (CLI, conditional on cli/**/*.go) (fast gate before push, skipped in pre-commit.ci — dedicated CI jobs already run these).
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Applies to web/** : Web dashboard: Node.js 20+, dependencies in web/package.json (Vue 3, PrimeVue, Tailwind CSS, Pinia, VueFlow, ECharts, Axios, vue-draggable-plus, Vitest, fast-check, ESLint, vue-tsc).
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T12:42:32.168Z
Learning: Applies to web/src/**/*.tsx : Do not recreate inline status indicators — use `<StatusBadge>`. Do not build card-with-header layouts from scratch — use `<SectionCard>`. Do not create metric displays with inline `text-metric font-bold` — use `<MetricCard>`. Do not render initials circles manually — use `<Avatar>`. Do not create complex (>8 line) JSX inside `.map()` — extract to a shared component.
📚 Learning: 2026-03-28T12:42:32.168Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T12:42:32.168Z
Learning: Applies to web/src/**/*.tsx : Do not recreate inline status indicators — use `<StatusBadge>`. Do not build card-with-header layouts from scratch — use `<SectionCard>`. Do not create metric displays with inline `text-metric font-bold` — use `<MetricCard>`. Do not render initials circles manually — use `<Avatar>`. Do not create complex (>8 line) JSX inside `.map()` — extract to a shared component.
Applied to files:
web/src/pages/providers/ProviderFormDrawer.tsx
📚 Learning: 2026-03-28T12:42:32.168Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T12:42:32.168Z
Learning: Applies to **/*.{ts,tsx} : Always reuse existing components from `web/src/components/ui/` before creating new ones. Refer to the Web Dashboard Design System component inventory (StatusBadge, MetricCard, Sparkline, SectionCard, AgentCard, DeptHealthBar, ProgressGauge, StatPill, Avatar, Button, Toast, Skeleton variants, EmptyState, ErrorBoundary, ConfirmDialog, CommandPalette, InlineEdit, AnimatedPresence, StaggerGroup/Item, Drawer, InputField, SelectField, SliderField, ToggleField, TaskStatusIndicator, PriorityBadge, ProviderHealthBadge) for all page compositions.
Applied to files:
web/src/pages/providers/ProviderFormDrawer.tsx
📚 Learning: 2026-03-28T12:42:32.168Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-28T12:42:32.168Z
Learning: Applies to web/package.json : Require Node.js 22+, TypeScript 6.0+. Core dependencies: React 19, react-router, shadcn/ui, Radix UI, Tailwind CSS 4, Zustand, tanstack/react-query, xyflow/react, dagrejs/dagre, dnd-kit, Recharts, Framer Motion, cmdk, Axios, Lucide React, fontsource-variable/geist, fontsource-variable/geist-mono. Dev/test: Storybook 10, Vitest, fast-check, ESLint, eslint-react/eslint-plugin, eslint-plugin-security.
Applied to files:
web/src/pages/providers/ProviderFormDrawer.tsx
🔇 Additional comments (1)
web/src/hooks/useApprovalsData.ts (1)
74-78: Polling effect dependency fix looks correct.Using
polling.start/polling.stopin the dependency array (Line 78) is a solid fix to avoid re-running the effect due to unstable object identity while preserving correct start/cleanup behavior.
🤖 I have created a release *beep* *boop* --- #MAJOR CHANGES; We got a somewhat working webui :) ## [0.5.0](v0.4.9...v0.5.0) (2026-03-30) ### Features * add analytics trends and budget forecast API endpoints ([#798](#798)) ([16b61f5](16b61f5)) * add department policies to default templates ([#852](#852)) ([7a41548](7a41548)) * add remaining activity event types (task_started, tool_used, delegation, cost_incurred) ([#832](#832)) ([4252fac](4252fac)) * agent performance, activity, and history API endpoints ([#811](#811)) ([9b75c1d](9b75c1d)) * Agent Profiles and Detail pages (biography, career, performance) ([#874](#874)) ([62d7880](62d7880)) * app shell, Storybook, and CI/CD pipeline ([#819](#819)) ([d4dde90](d4dde90)) * Approvals page with risk grouping, urgency indicators, batch actions ([#889](#889)) ([4e9673d](4e9673d)) * Budget Panel page (P&L dashboard, breakdown charts, forecast) ([#890](#890)) ([b63b0f1](b63b0f1)) * build infrastructure layer (API client, auth, WebSocket) ([#815](#815)) ([9f01d3e](9f01d3e)) * CLI global options infrastructure, UI modes, exit codes, env vars ([#891](#891)) ([fef4fc5](fef4fc5)) * CodeMirror editor and theme preferences toggle ([#905](#905), [#807](#807)) ([#909](#909)) ([41fbedc](41fbedc)) * Company page (department/agent management) ([#888](#888)) ([cfb88b0](cfb88b0)) * comprehensive hint coverage across all CLI commands ([#900](#900)) ([937974e](937974e)) * config system extensions, per-command flags for init/start/stop/status/logs ([#895](#895)) ([32f83fe](32f83fe)) * configurable currency system replacing hardcoded USD ([#854](#854)) ([b372551](b372551)) * Dashboard page (metric cards, activity feed, budget burn) ([#861](#861)) ([7d519d5](7d519d5)) * department health, provider status, and activity feed endpoints ([#818](#818)) ([6d5f196](6d5f196)) * design tokens and core UI components ([#833](#833)) ([ed887f2](ed887f2)) * extend approval, meeting, and budget API responses ([#834](#834)) ([31472bf](31472bf)) * frontend polish -- real-time UX, accessibility, responsive, performance ([#790](#790), [#792](#792), [#791](#791), [#793](#793)) ([#917](#917)) ([f04a537](f04a537)) * implement human roles and access control levels ([#856](#856)) ([d6d8a06](d6d8a06)) * implement semantic conflict detection in workspace merge ([#860](#860)) ([d97283b](d97283b)) * interaction components and animation patterns ([#853](#853)) ([82d4b01](82d4b01)) * Login page + first-run bootstrap + Company page ([#789](#789), [#888](#888)) ([#896](#896)) ([8758e8d](8758e8d)) * Meetings page with timeline viz, token bars, contribution formatting ([#788](#788)) ([#904](#904)) ([b207f46](b207f46)) * Messages page with threading, channel badges, sender indicators ([#787](#787)) ([#903](#903)) ([28293ad](28293ad)) * Org Chart force-directed view and drag-drop reassignment ([#872](#872), [#873](#873)) ([#912](#912)) ([a68a938](a68a938)) * Org Chart page (living nodes, status, CRUD, department health) ([#870](#870)) ([0acbdae](0acbdae)) * per-command flags for remaining commands, auto-behavior wiring, help/discoverability ([#897](#897)) ([3f7afa2](3f7afa2)) * Providers page with backend rework -- health, CRUD, subscription auth ([#893](#893)) ([9f8dd98](9f8dd98)) * scaffold React + Vite + TypeScript + Tailwind project ([#799](#799)) ([bd151aa](bd151aa)) * Settings page with search, dependency indicators, grouped rendering ([#784](#784)) ([#902](#902)) ([a7b9870](a7b9870)) * Setup Wizard rebuild with template comparison, cost estimator, theme customization ([#879](#879)) ([ae8b50b](ae8b50b)) * setup wizard UX -- template filters, card metadata, provider form reuse ([#910](#910)) ([7f04676](7f04676)) * setup wizard UX overhaul -- mode choice, step reorder, provider fixes ([#907](#907)) ([ee964c4](ee964c4)) * structured ModelRequirement in template agent configs ([#795](#795)) ([7433548](7433548)) * Task Board page (rich Kanban, filtering, dependency viz) ([#871](#871)) ([04a19b0](04a19b0)) ### Bug Fixes * align frontend types with backend and debounce WS refetches ([#916](#916)) ([134c11b](134c11b)) * auto-cleanup targets newly pulled images instead of old ones ([#884](#884)) ([50e6591](50e6591)) * correct wipe backup-skip flow and harden error handling ([#808](#808)) ([c05860f](c05860f)) * improve provider setup in wizard, subscription auth, dashboard bugs ([#914](#914)) ([87bf8e6](87bf8e6)) * improve update channel detection and add config get command ([#814](#814)) ([6b137f0](6b137f0)) * resolve all ESLint warnings, add zero-warnings enforcement ([#899](#899)) ([079b46a](079b46a)) * subscription auth uses api_key, base URL optional for cloud providers ([#915](#915)) ([f0098dd](f0098dd)) ### Refactoring * semantic analyzer cleanup -- shared filtering, concurrency, extraction ([#908](#908)) ([81372bf](81372bf)) ### Documentation * brand identity and UX design system from [#765](#765) exploration ([#804](#804)) ([389a9f4](389a9f4)) * page structure and information architecture for v0.5.0 dashboard ([#809](#809)) ([f8d6d4a](f8d6d4a)) * write UX design guidelines with WCAG-verified color system ([#816](#816)) ([4a4594e](4a4594e)) ### Tests * add unit tests for agent hooks and page components ([#875](#875)) ([#901](#901)) ([1d81546](1d81546)) ### CI/CD * bump actions/deploy-pages from 4.0.5 to 5.0.0 in the major group ([#831](#831)) ([01c19de](01c19de)) * bump astral-sh/setup-uv from 7.6.0 to 8.0.0 in /.github/actions/setup-python-uv in the all group ([#920](#920)) ([5f6ba54](5f6ba54)) * bump codecov/codecov-action from 5.5.3 to 6.0.0 in the major group ([#868](#868)) ([f22a181](f22a181)) * bump github/codeql-action from 4.34.1 to 4.35.0 in the all group ([#883](#883)) ([87a4890](87a4890)) * bump sigstore/cosign-installer from 4.1.0 to 4.1.1 in the minor-and-patch group ([#830](#830)) ([7a69050](7a69050)) * bump the all group with 3 updates ([#923](#923)) ([ff27c8e](ff27c8e)) * bump wrangler from 4.76.0 to 4.77.0 in /.github in the minor-and-patch group ([#822](#822)) ([07d43eb](07d43eb)) * bump wrangler from 4.77.0 to 4.78.0 in /.github in the all group ([#882](#882)) ([f84118d](f84118d)) ### Maintenance * add design system enforcement hook and component inventory ([#846](#846)) ([15abc43](15abc43)) * add dev-only auth bypass for frontend testing ([#885](#885)) ([6cdcd8a](6cdcd8a)) * add pre-push rebase check hook ([#855](#855)) ([b637a04](b637a04)) * backend hardening -- eviction/size-caps and model validation ([#911](#911)) ([81253d9](81253d9)) * bump axios from 1.13.6 to 1.14.0 in /web in the all group across 1 directory ([#922](#922)) ([b1b0232](b1b0232)) * bump brace-expansion from 5.0.4 to 5.0.5 in /web ([#862](#862)) ([ba4a565](ba4a565)) * bump eslint-plugin-react-refresh from 0.4.26 to 0.5.2 in /web ([#801](#801)) ([7574bb5](7574bb5)) * bump faker from 40.11.0 to 40.11.1 in the minor-and-patch group ([#803](#803)) ([14d322e](14d322e)) * bump https://github.com/astral-sh/ruff-pre-commit from v0.15.7 to 0.15.8 ([#864](#864)) ([f52901e](f52901e)) * bump nginxinc/nginx-unprivileged from `6582a34` to `f99cc61` in /docker/web in the all group ([#919](#919)) ([df85e4f](df85e4f)) * bump nginxinc/nginx-unprivileged from `ccbac1a` to `6582a34` in /docker/web ([#800](#800)) ([f4e9450](f4e9450)) * bump node from `44bcbf4` to `71be405` in /docker/sandbox ([#827](#827)) ([91bec67](91bec67)) * bump node from `5209bca` to `cf38e1f` in /docker/web ([#863](#863)) ([66d6043](66d6043)) * bump picomatch in /site ([#842](#842)) ([5f20bcc](5f20bcc)) * bump recharts 2->3 and @types/node 22->25 in /web ([#802](#802)) ([a908800](a908800)) * Bump requests from 2.32.5 to 2.33.0 ([#843](#843)) ([41daf69](41daf69)) * bump smol-toml from 1.6.0 to 1.6.1 in /site ([#826](#826)) ([3e5dbe4](3e5dbe4)) * bump the all group with 3 updates ([#921](#921)) ([7bace0b](7bace0b)) * bump the minor-and-patch group across 1 directory with 2 updates ([#829](#829)) ([93e611f](93e611f)) * bump the minor-and-patch group across 1 directory with 3 updates ([#841](#841)) ([7010c8e](7010c8e)) * bump the minor-and-patch group across 1 directory with 3 updates ([#869](#869)) ([548cee5](548cee5)) * bump the minor-and-patch group in /site with 2 updates ([#865](#865)) ([9558101](9558101)) * bump the minor-and-patch group with 2 updates ([#867](#867)) ([4830706](4830706)) * consolidate Dependabot groups to 1 PR per ecosystem ([06d2556](06d2556)) * consolidate Dependabot groups to 1 PR per ecosystem ([#881](#881)) ([06d2556](06d2556)) * improve worktree skill with full dep sync and status enhancements ([#906](#906)) ([772c625](772c625)) * remove Vue remnants and document framework decision ([#851](#851)) ([bf2adf6](bf2adf6)) * update web dependencies and fix brace-expansion CVE ([#880](#880)) ([a7a0ed6](a7a0ed6)) * upgrade to Storybook 10 and TypeScript 6 ([#845](#845)) ([52d95f2](52d95f2)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Summary
useEffect-based state sync with render-phase patterns usinguseReffor previous-value tracking -- React's recommended approach for derived state, eliminatesset-state-in-effectwarningsusePollingreturn stability -- memoize return object so consumers can safely use[polling]as a dependency without infinite re-render loopseslint-webpre-commit/pre-push hook (--max-warnings 0) to prevent warning regressions at commit time--max-warnings 0tonpm run lintscript for parity with the local hookeslint-webhookTest plan
--max-warnings 0)tsc -bcleaneslint-webruns and passes on commiteslint-webruns and passes on push🤖 Generated with Claude Code