Skip to content

feat: Org Chart page (living nodes, status, CRUD, department health)#870

Merged
Aureliolo merged 17 commits intomainfrom
feat/org-chart-page
Mar 27, 2026
Merged

feat: Org Chart page (living nodes, status, CRUD, department health)#870
Aureliolo merged 17 commits intomainfrom
feat/org-chart-page

Conversation

@Aureliolo
Copy link
Copy Markdown
Owner

Summary

  • Implement the Org Chart page with React Flow (@xyflow/react v12) showing a living organizational diagram with real-time agent status
  • Custom nodes: AgentNode (with StatusBadge + Avatar), CeoNode (accent-styled), DepartmentGroupNode (health-colored overlay with stats)
  • Auto-layout via @dagrejs/dagre hierarchical tree layout -- no manual positioning needed
  • Department health overlay with color-coded backgrounds (green/amber/red) and stats bar (agents, active, tasks, cost)
  • CRUD scaffolding via right-click context menu (edit/remove agent, assign department, department CRUD) with stub API calls
  • Click-to-drill: clicking agent nodes navigates to Agent Detail page via React Router
  • Pan/zoom with localStorage viewport persistence
  • Hierarchy/Communication view toggle (communication view shows feedback toast -- awaiting communication data APIs)
  • Zustand stores populated: useCompanyStore (company config + department health), useAgentsStore (runtime status from WebSocket)
  • useOrgChartData composite hook following useDashboardData pattern (stores + WS + polling)
  • Pure utility functions: buildOrgTree (derives hierarchy from seniority + teams), applyDagreLayout, resolveRuntimeStatus
  • 7 Storybook story files for all page-scoped components
  • 48 new tests across 10 test files (pure logic, stores, components, page)

Pre-reviewed by 5 agents, 15 findings addressed

  • Frontend reviewer: useNavigate instead of window.location.href, SeniorityLevel type, layout.ts dead code + mutation fix
  • Security reviewer: WebSocket payload runtime validation, localStorage shape validation
  • Test analyzer: Store tests added, loading-with-nodes + c_suite fallback test cases
  • Docs consistency: CLAUDE.md Package Structure updated
  • Issue verifier: onNodeClick handler added for click-to-drill, viewMode toast feedback

Test plan

  • npm --prefix web run type-check -- 0 errors
  • npm --prefix web run lint -- 0 errors (1 pre-existing warning)
  • npm --prefix web run test -- 683 tests pass (48 new)
  • Visual: npm --prefix web run storybook -- verify AgentNode, CeoNode, DepartmentGroupNode, Toolbar, Skeleton stories
  • Visual: npm --prefix web run dev -- navigate to /org, verify chart renders with mock/real data
  • Verify right-click context menu appears on nodes
  • Verify click on agent node navigates to /agents/:name
  • Verify pan/zoom persists across page navigation

Closes #778
Closes #674

🤖 Generated with Claude Code

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 27, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 7ae4b246-24c7-4e49-b78b-77a2c43e52cb

📥 Commits

Reviewing files that changed from the base of the PR and between f63a7a3 and 258f8c9.

📒 Files selected for processing (2)
  • web/src/__tests__/pages/org/DepartmentStatsBar.test.tsx
  • web/src/hooks/useOrgChartData.ts
📜 Recent 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 Backend
  • GitHub Check: Build Web
  • GitHub Check: Build Sandbox
  • GitHub Check: Dependency Review
  • GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (1)
web/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

web/src/**/*.{ts,tsx}: ALWAYS reuse existing components from web/src/components/ui/ (StatusBadge, MetricCard, Sparkline, SectionCard, AgentCard, etc.) before creating new ones
Use Tailwind semantic classes (text-foreground, bg-card, text-accent, etc.) or CSS variables (var(--so-*)) for colors; NEVER hardcode hex or rgba values
Use font-sans or font-mono for typography; NEVER set fontFamily directly in component code
Use density-aware spacing tokens (p-card, gap-section-gap, gap-grid-gap) or standard Tailwind spacing; NEVER hardcode pixel values for layout spacing
Use token variables for shadows and borders (var(--so-shadow-card-hover), border-border, border-bright); NEVER hardcode values
Do NOT recreate status dots inline -- use <StatusBadge>; do NOT build card-with-header layouts from scratch -- use <SectionCard>; do NOT create metric displays with hardcoded styles -- use <MetricCard>
Do NOT create complex (>8 line) JSX inside .map() -- extract to a shared component in web/src/components/ui/
Use TypeScript 6.0+ strict mode with proper tsconfig.json configuration: remove deprecated baseUrl, enable paths for imports, explicitly list types, use moduleResolution: 'bundler', keep strict: true
Set parameters.a11y.test: 'error' | 'todo' | 'off' in Storybook stories to enforce WCAG compliance (set globally in preview.tsx)

Files:

  • web/src/__tests__/pages/org/DepartmentStatsBar.test.tsx
  • web/src/hooks/useOrgChartData.ts
🧠 Learnings (3)
📓 Common learnings
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/).
📚 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/src/__tests__/pages/org/DepartmentStatsBar.test.tsx
📚 Learning: 2026-03-27T14:30:49.093Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T14:30:49.093Z
Learning: Applies to web/src/**/*.{ts,tsx} : Do NOT recreate status dots inline -- use `<StatusBadge>`; do NOT build card-with-header layouts from scratch -- use `<SectionCard>`; do NOT create metric displays with hardcoded styles -- use `<MetricCard>`

Applied to files:

  • web/src/__tests__/pages/org/DepartmentStatsBar.test.tsx
  • web/src/hooks/useOrgChartData.ts
🔇 Additional comments (10)
web/src/__tests__/pages/org/DepartmentStatsBar.test.tsx (4)

7-15: Stat value/label coverage is clear and efficient.

Single-render assertions here are clean and maintain good readability.


17-27: Currency rendering tests are solid.

Good coverage of both default USD behavior and explicit currency forwarding.


29-32: Null-cost guard behavior is correctly verified.

This protects the conditional rendering contract for the Cost metric.


34-37: data-testid contract check looks good.

Keeps selector stability for downstream tests.

web/src/hooks/useOrgChartData.ts (6)

47-47: The ESLint disable rule name is still incorrect.

This was previously flagged: @eslint-react/exhaustive-deps does not exist in @eslint-react/eslint-plugin. The exhaustive-deps rule comes from eslint-plugin-react-hooks and should be referenced as react-hooks/exhaustive-deps. Currently this comment has no effect.


1-12: LGTM — Clean imports and well-scoped constants.

The removal of the unused 'system' channel from ORG_CHANNELS addresses previous feedback. The 30-second polling interval is reasonable for department health refresh.


14-28: LGTM — Well-typed interface and optimized store selectors.

The selective subscriptions (useCompanyStore((s) => s.config), etc.) ensure the component only re-renders when specific slices change, following Zustand best practices.


50-61: LGTM — Correct WebSocket binding pattern.

Using getState() inside the handler ensures fresh store access without stale closure issues. Dispatching to both stores allows each to handle the event types it cares about (company store for agent.hired/agent.fired, agents store for agent.status_changed).


67-73: LGTM — Efficient memoization with correct dependencies.

The derived graph computation only runs when source data changes. The early return when config is absent avoids unnecessary work during initial load.


75-82: LGTM — Return shape matches interface contract.

All required fields are provided: graph data (nodes, edges), loading states (loading), error handling (error), and WebSocket status (wsConnected, wsSetupError).


Walkthrough

Replaces the Org Chart placeholder with a full React Flow–based implementation: OrgChartPage (and OrgChartInner) plus a new hook useOrgChartData that builds nodes/edges from store state. Adds node renderers (AgentNode, CeoNode, DepartmentGroupNode, DepartmentStatsBar), UI pieces (OrgChartToolbar, OrgChartSkeleton, NodeContextMenu, HierarchyEdge), layout and graph utilities (applyDagreLayout, buildOrgTree, status-mapping), and enhanced Zustand stores (company, agents) with WebSocket handling and per-agent runtime status. Adds Storybook stories, many Vitest tests, imports XYFlow/React Flow CSS, and updates web/package.json with @dagrejs/dagre and @types/d3-hierarchy.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.45% which is insufficient. The required threshold is 40.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: implementing an Org Chart page with living nodes, real-time status updates, CRUD operations, and department health visualization.
Description check ✅ Passed The description is comprehensive and directly related to the changeset, covering implementation details, test coverage, and pre-review findings.
Linked Issues check ✅ Passed The PR successfully addresses core requirements from #778 and #674: org chart with React Flow, living status nodes, department health visualization, auto-layout via dagre, pan/zoom with persistence, click-to-drill navigation, right-click context menus for CRUD scaffolding, WebSocket integration, and comprehensive test coverage.
Out of Scope Changes check ✅ Passed All changes are in scope: new org chart components, stores (company/agents), hooks (useOrgChartData), utilities (buildOrgTree/layout/status-mapping), Storybook stories, tests, CSS imports, and package.json dependency updates for @dagrejs/dagre and @types/d3-hierarchy align with the org chart implementation.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 27, 2026

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Snapshot Warnings

⚠️: No snapshots were found for the head SHA 258f8c9.
Ensure 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.

OpenSSF Scorecard

PackageVersionScoreDetails
npm/@dagrejs/dagre 3.0.0 🟢 4.3
Details
CheckScoreReason
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Code-Review⚠️ 2Found 4/18 approved changesets -- score normalized to 2
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
Maintained🟢 1027 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10
Packaging⚠️ -1packaging workflow not detected
Binary-Artifacts🟢 10no binaries found in the repo
Pinned-Dependencies⚠️ 0dependency not pinned by hash detected -- score normalized to 0
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Security-Policy⚠️ 0security policy file not detected
Fuzzing⚠️ 0project is not fuzzed
License🟢 10license file detected
Signed-Releases⚠️ -1no releases found
Branch-Protection🟢 3branch protection is not maximal on development and all release branches
SAST⚠️ 0SAST tool is not run on all commits -- score normalized to 0
npm/@dagrejs/graphlib 4.0.1 🟢 3.9
Details
CheckScoreReason
Packaging⚠️ -1packaging workflow not detected
Code-Review⚠️ 1Found 4/21 approved changesets -- score normalized to 1
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Maintained🟢 1030 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
Binary-Artifacts🟢 10no binaries found in the repo
Pinned-Dependencies⚠️ 0dependency not pinned by hash detected -- score normalized to 0
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Security-Policy⚠️ 0security policy file not detected
Fuzzing⚠️ 0project is not fuzzed
License🟢 10license file detected
Signed-Releases⚠️ -1no releases found
Branch-Protection⚠️ 0branch protection not enabled on development/release branches
SAST⚠️ 0SAST tool is not run on all commits -- score normalized to 0
npm/@types/d3-hierarchy 3.1.7 🟢 6.5
Details
CheckScoreReason
Packaging⚠️ -1packaging workflow not detected
Code-Review🟢 8Found 26/30 approved changesets -- score normalized to 8
Maintained🟢 1030 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
License🟢 9license file detected
Security-Policy🟢 10security policy file detected
Signed-Releases⚠️ -1no releases found
Branch-Protection⚠️ -1internal error: error during branchesHandler.setup: internal error: some github tokens can't read classic branch protection rules: https://github.com/ossf/scorecard-action/blob/main/docs/authentication/fine-grained-auth-token.md
SAST⚠️ 0SAST tool is not run on all commits -- score normalized to 0
Pinned-Dependencies🟢 8dependency not pinned by hash detected -- score normalized to 8
Binary-Artifacts🟢 10no binaries found in the repo
Fuzzing⚠️ 0project is not fuzzed

Scanned Files

  • web/package-lock.json

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request implements a comprehensive Org Chart feature using React Flow and Dagre for hierarchical layout. Key additions include specialized node components (Agent, CEO, Department), a custom hook for data management with real-time WebSocket updates, and updated Zustand stores for agent and company data. The implementation is supported by extensive unit tests and Storybook stories. Review feedback suggests improving type safety when accessing node data and replacing magic numbers with named constants in the layout logic to enhance maintainability.

const handleDelete = useCallback(
(nodeId: string) => {
const node = nodes.find((n) => n.id === nodeId)
const label = node ? String((node.data as { name?: string; displayName?: string }).name ?? (node.data as { displayName?: string }).displayName ?? nodeId) : nodeId
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The type assertion here is not as safe as it could be. Since node.data is essentially any from React Flow's perspective, you're casting it to a loose shape ({ name?: string; displayName?: string }). This can be brittle if the node data structures change.

A more robust approach would be to use type guards or property checks (e.g., 'name' in node.data) to safely access name or displayName based on the well-defined data types for your nodes (AgentNodeData, DepartmentGroupData). This would improve maintainability and type safety.

}

const groupX = minX - padding
const groupY = minY - padding - 40
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The magic number 40 is used here and on line 97 to account for the vertical space occupied by the department group node's header. Hardcoding this value makes the layout logic brittle. If the styling of DepartmentGroupNode changes, this value might need to be updated here as well, which is easy to forget.

Consider defining this value as a named constant at the top of the file (e.g., const GROUP_NODE_HEADER_HEIGHT = 40) and using it here. This would improve readability and maintainability.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 24

🤖 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/__tests__/pages/org/build-org-tree.test.ts`:
- Around line 284-294: The test mutates config.company_name and then passes a
spread with the same value to buildOrgTree, which is redundant; remove the
standalone assignment config.company_name = 'Acme Inc' and keep only the spread
when calling buildOrgTree (refer to makeConfig, config, and buildOrgTree in the
"includes companyName in CEO node data" test) so the test sets company_name
exactly once without mutation.

In `@web/src/__tests__/pages/org/layout.test.ts`:
- Around line 67-80: The test title is misleading: update the it(...)
description in the test that uses makeNode/makeEdge and calls applyDagreLayout
so it accurately reflects the asserted behavior (the department node is returned
with a position rather than being excluded). Change the string from "excludes
department group nodes from dagre layout" to something like "handles department
group nodes separately from dagre layout" or "returns department group nodes
with positions" so the name matches the assertions using result.find(...),
dept.position, and expect(result).toHaveLength(3).

In `@web/src/__tests__/pages/org/NodeContextMenu.test.tsx`:
- Around line 5-11: The shared mock baseProps.onClose in the NodeContextMenu
test suite should be reset before each test to avoid state leakage; inside the
describe('NodeContextMenu') block add a beforeEach that calls vi.resetAllMocks()
or reassigns baseProps.onClose = vi.fn(), ensuring each test starts with a fresh
mock for the onClose handler referenced by baseProps used in the tests.

In `@web/src/__tests__/pages/org/OrgChartToolbar.test.tsx`:
- Around line 6-12: The test currently defines shared mock functions in the
module-scope constant defaultProps which can leak call state between tests;
replace this with a factory or recreate props per test (e.g., implement a
makeDefaultProps() that returns a new object with fresh vi.fn() for
onViewModeChange, onFitView, onZoomIn, onZoomOut) or call vi.resetAllMocks() in
a beforeEach; update references to use the new factory or per-test props instead
of the shared defaultProps constant.

In `@web/src/hooks/useOrgChartData.ts`:
- Around line 45-49: The ESLint disable is referencing a non-existent rule name;
update the hook to either install the missing linter plugin
`eslint-plugin-react-hooks` and change the comment to `//
eslint-disable-next-line react-hooks/exhaustive-deps` or remove the disable
entirely if you want the `useEffect` dependency check; locate the useEffect
where `polling.start()` / `polling.stop()` are called inside `useOrgChartData`
and apply the chosen change (add the plugin to devDependencies and enable it in
ESLint config if keeping the disable, or simply delete the incorrect `//
eslint-disable-next-line `@eslint-react/exhaustive-deps`` line).

In `@web/src/pages/org/AgentNode.stories.tsx`:
- Around line 34-38: The Storybook story meta for AgentNode is missing
accessibility test configuration; update the exported meta object (the const
meta that satisfies Meta<typeof Wrapper>) to include a parameters field with an
a11y.test configuration (e.g., parameters: { a11y: { test: /* desired test
config or presets */ } }) so Storybook runs the accessibility checks for the
Wrapper component/story. Ensure the new parameters.a11y.test key is present
alongside title/component/tags in the meta object.

In `@web/src/pages/org/AgentNode.tsx`:
- Line 27: The AgentNode component currently uses hardcoded pixel width utility
classes ('min-w-[140px] max-w-[180px]')—replace these with the project's
density-aware sizing or standard Tailwind spacing utilities instead; update the
class list in the AgentNode JSX where those tokens appear to use the appropriate
density token (or Tailwind equivalents like min-w-36 / max-w-44) so layout
follows design tokens and responsive/density rules, and verify the node still
renders correctly across breakpoints.

In `@web/src/pages/org/build-org-tree.ts`:
- Around line 100-119: The department node currently defaults missing health to
100%/0 which hides transient API failures; in the nodes.push call that builds
DepartmentGroupData (refer to healthMap.get(dept.name), groupId, and the
nodes.push object), change the health-derived fields so that when health is
undefined you set healthPercent, taskCount and costUsd to null (or leave
undefined) instead of 100/0; preserve agentCount and activeCount logic but
ensure DepartmentGroupData’s healthPercent/taskCount/costUsd remain nullable so
the renderer can show a neutral/loading/error state.
- Around line 96-99: The loop in build-org-tree is currently skipping
departments with no members (the check using deptMembers.length === 0), which
prevents newly created empty departments from rendering; remove that
early-continue so every department in config.departments is processed and
included even when deptAgents.get(dept.name) returns an empty array, ensuring
empty departments are represented (the existing empty-group handling in
web/src/pages/org/layout.ts will take care of rendering them). Locate the for
(const dept of config.departments) block and delete or disable the if
(deptMembers.length === 0) continue guard so deptMembers (possibly []) is still
used to create the department node.

In `@web/src/pages/org/CeoNode.stories.tsx`:
- Around line 34-38: The Storybook story's meta object (const meta) lacks
accessibility test configuration; update the meta for the CeoNode story to
include parameters.a11y.test with the desired a11y rule set (e.g., 'wcag2a' or
your project's configured tests) so Storybook runs automated accessibility
checks — modify the existing meta (satisfies Meta<typeof Wrapper>) to add a
parameters field containing an a11y.test entry referencing the configured tests
for Wrapper/CeoNode.
- Around line 43-69: Add two new Story exports for the missing runtime statuses
by copying the existing Active/Idle pattern: create exports named Error and
Offline that set args.data.runtimeStatus to 'error' and 'offline' respectively
(and adjust other fields if desired). Ensure they follow the same shape as the
existing Active and Idle stories (export const Error: Story = { args: { data: {
... } } } and export const Offline: Story = { ... }) so CeoNode/StatusBadge
renders the error and offline visuals in Storybook.

In `@web/src/pages/org/CeoNode.tsx`:
- Line 23: Update the Tailwind important modifier syntax used in the CeoNode
component: replace the old prefix-style modifiers in the Handle JSX (className
on Handle using "!bg-accent !size-1.5") with Tailwind v4 postfix syntax (e.g.,
"bg-accent! size-1.5!"); locate the Handle element (Handle type="target"
position={Position.Top}) and change its className accordingly so it uses postfix
"!" after each utility.

In `@web/src/pages/org/DepartmentGroupNode.stories.tsx`:
- Around line 35-42: The story meta object for the DepartmentGroupNode story
(the const meta and its relation to Wrapper) is missing the Storybook a11y test
configuration; update the meta to include a parameters property with an
a11y.test key (set to one of the allowed values: 'error' | 'todo' | 'off') so
Storybook will run accessibility tests for this component, e.g. add parameters:
{ a11y: { test: 'error' } } to the existing meta object.

In `@web/src/pages/org/DepartmentStatsBar.tsx`:
- Around line 5-11: The component props (DepartmentStatsBarProps) currently fall
back to EUR when currency is undefined, which conflicts with the costUsd prop
semantics; change the formatting logic in DepartmentStatsBar (where costUsd and
currency are used, e.g., the money formatting call around line ~27) to default
to "USD" when currency is not provided or when costUsd is present (i.e., use
currency ?? "USD" or detect costUsd !== null to force "USD"), and ensure the
Intl.NumberFormat/formatMoney call uses that resolved currency so the displayed
symbol/value correctly reflects USD.

In `@web/src/pages/org/layout.ts`:
- Around line 43-47: The Dagre layout is being computed with fallback sizes
because measured dimensions are not yet available; update applyDagreLayout usage
so layout runs with real node sizes: either (preferred) have useOrgChartData
re-run applyDagreLayout in a useEffect when nodes gain measured dimensions
(watch a measuredAvailable flag or node.measured changes) instead of in a
useMemo, or ensure buildOrgTree supplies stable width/height in node.data and
change the layout code (the loop that calls g.setNode for leaf nodes) to use
those stable dimensions (e.g., node.data.width/height) rather than node.measured
so Dagre computes correct spacing and group bounds.

In `@web/src/pages/org/NodeContextMenu.stories.tsx`:
- Around line 20-36: Add a third story named CeoMenu to mirror AgentMenu and
DepartmentMenu so the NodeContextMenu component's 'ceo' nodeType is covered;
export const CeoMenu: Story = { args: { nodeId: 'ceo-1', nodeType: 'ceo',
position: { x: 100, y: 50 }, onClose: () => {} } } (use the same shape/props as
AgentMenu and DepartmentMenu).
- Around line 4-15: Update the Storybook meta object for NodeContextMenu to
include an accessibility test configuration by adding a parameters.a11y.test
entry; modify the existing meta constant (the object assigned to meta that
"satisfies Meta<typeof NodeContextMenu>") to include a parameters property with
a11y.test set to the desired test flags/configuration so Storybook runs
accessibility checks for the NodeContextMenu story.

In `@web/src/pages/org/NodeContextMenu.tsx`:
- Around line 110-113: The menu buttons in NodeContextMenu (the JSX <button>
rendered for each menu item using key={item.label} and onClick={item.action})
lack an explicit type and can accidentally submit enclosing forms; update the
button element to include type="button" so these menu actions do not trigger
form submission when rendered inside a form context.
- Line 99: The nodeType check in NodeContextMenu.tsx currently maps only
'department' to departmentItems and everything else (including 'ceo') to
agentItems; update the selection logic so 'ceo' does not inherit agent CRUD
actions—either map 'ceo' to departmentItems or a new ceoItems set. Concretely,
change the conditional that assigns items (referencing nodeType,
departmentItems, agentItems) to explicitly handle 'ceo' (e.g., nodeType ===
'department' || nodeType === 'ceo') or introduce and use a distinct ceoItems
array and use that when nodeType === 'ceo'.

In `@web/src/pages/org/OrgChartSkeleton.stories.tsx`:
- Around line 8-14: The decorator currently sets the background via inline style
in the decorators array ((Story) => (<div style={{ height: 400, background:
'var(--background)' }}>...)), so remove the inline background property and leave
only the height styling; rely on Storybook's global backgrounds config or, if
this story needs a custom background, add a story-level parameters.backgrounds
entry instead of an inline style.

In `@web/src/pages/org/OrgChartToolbar.tsx`:
- Around line 33-52: The two toggle Buttons in OrgChartToolbar (the ones using
GitBranch and Network) only indicate active state visually; update each Button
to expose that state to assistive tech by adding an aria-pressed prop set to
true when viewMode matches that button's mode and false otherwise (e.g.,
aria-pressed={viewMode === 'hierarchy'} for the hierarchy Button and
aria-pressed={viewMode === 'force'} for the communication Button), keeping
existing onViewModeChange handlers and aria-labels intact.

In `@web/src/pages/org/status-mapping.ts`:
- Around line 8-18: In mapHrToRuntime the cases 'onboarding' and 'active' both
return 'idle'—combine them into a single fall-through case (e.g., case
'onboarding': case 'active': return 'idle') inside the mapHrToRuntime function
to improve readability while preserving behavior; update the switch in
mapHrToRuntime (types AgentStatus / AgentRuntimeStatus remain unchanged).

In `@web/src/pages/OrgChartPage.tsx`:
- Around line 110-118: handleNodeClick uses a type assertion on node.data to
access name which can throw if data is missing or malformed; update the
handleNodeClick callback to defensively check node.data and that (node.data as
any).name is a string before calling navigate (keep using
encodeURIComponent(name)), and if the guard fails simply return early or log a
warning; locate the handleNodeClick function and replace the direct assertion
with a safe extraction/guard that prevents navigation when name is absent while
keeping behavior for valid agent/ceo nodes (buildOrgTree remains the source of
truth).

In `@web/src/stores/company.ts`:
- Around line 32-45: fetchDepartmentHealths currently calls listDepartments({
limit: 100 }) which only returns the first page and misses departments; update
fetchDepartmentHealths to page through the full list (using listDepartments'
pagination cursor/nextToken or similar) and accumulate all departments before
mapping to getDepartmentHealth, or alternatively drive the health lookups from
config.departments to guarantee alignment with the configured org; ensure you
replace the single listDepartments call in fetchDepartmentHealths with a loop or
helper that collects all pages (referencing listDepartments and
getDepartmentHealth) and then map over the complete array to create
healthPromises.
🪄 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: acfda971-3933-4a5d-993c-f1fee2224d96

📥 Commits

Reviewing files that changed from the base of the PR and between 7d519d5 and e199b1e.

⛔ Files ignored due to path filters (1)
  • web/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (35)
  • CLAUDE.md
  • web/package.json
  • web/src/__tests__/pages/org/DepartmentStatsBar.test.tsx
  • web/src/__tests__/pages/org/NodeContextMenu.test.tsx
  • web/src/__tests__/pages/org/OrgChartPage.test.tsx
  • web/src/__tests__/pages/org/OrgChartSkeleton.test.tsx
  • web/src/__tests__/pages/org/OrgChartToolbar.test.tsx
  • web/src/__tests__/pages/org/build-org-tree.test.ts
  • web/src/__tests__/pages/org/layout.test.ts
  • web/src/__tests__/pages/org/status-mapping.test.ts
  • web/src/__tests__/stores/agents.test.ts
  • web/src/__tests__/stores/company.test.ts
  • web/src/hooks/useOrgChartData.ts
  • web/src/pages/OrgChartPage.tsx
  • web/src/pages/org/AgentNode.stories.tsx
  • web/src/pages/org/AgentNode.tsx
  • web/src/pages/org/CeoNode.stories.tsx
  • web/src/pages/org/CeoNode.tsx
  • web/src/pages/org/DepartmentGroupNode.stories.tsx
  • web/src/pages/org/DepartmentGroupNode.tsx
  • web/src/pages/org/DepartmentStatsBar.stories.tsx
  • web/src/pages/org/DepartmentStatsBar.tsx
  • web/src/pages/org/HierarchyEdge.tsx
  • web/src/pages/org/NodeContextMenu.stories.tsx
  • web/src/pages/org/NodeContextMenu.tsx
  • web/src/pages/org/OrgChartSkeleton.stories.tsx
  • web/src/pages/org/OrgChartSkeleton.tsx
  • web/src/pages/org/OrgChartToolbar.stories.tsx
  • web/src/pages/org/OrgChartToolbar.tsx
  • web/src/pages/org/build-org-tree.ts
  • web/src/pages/org/layout.ts
  • web/src/pages/org/status-mapping.ts
  • web/src/stores/agents.ts
  • web/src/stores/company.ts
  • web/src/styles/global.css
📜 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 Backend
  • GitHub Check: Build Sandbox
  • GitHub Check: Dashboard Test
  • GitHub Check: Dependency Review
  • GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (8)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Use TypeScript 6+ with paths for module resolution (remove deprecated baseUrl); esModuleInterop is always true
In TypeScript, strict defaults to true and types defaults to []; do not auto-discover @types/* — must explicitly list needed types

Files:

  • web/src/__tests__/pages/org/OrgChartToolbar.test.tsx
  • web/src/pages/org/OrgChartSkeleton.tsx
  • web/src/__tests__/stores/agents.test.ts
  • web/src/pages/org/OrgChartToolbar.stories.tsx
  • web/src/__tests__/pages/org/OrgChartSkeleton.test.tsx
  • web/src/pages/org/OrgChartSkeleton.stories.tsx
  • web/src/pages/org/status-mapping.ts
  • web/src/pages/org/HierarchyEdge.tsx
  • web/src/pages/org/DepartmentGroupNode.stories.tsx
  • web/src/__tests__/pages/org/DepartmentStatsBar.test.tsx
  • web/src/pages/org/CeoNode.tsx
  • web/src/__tests__/pages/org/OrgChartPage.test.tsx
  • web/src/__tests__/pages/org/status-mapping.test.ts
  • web/src/pages/OrgChartPage.tsx
  • web/src/hooks/useOrgChartData.ts
  • web/src/__tests__/stores/company.test.ts
  • web/src/stores/agents.ts
  • web/src/pages/org/NodeContextMenu.stories.tsx
  • web/src/pages/org/layout.ts
  • web/src/pages/org/DepartmentStatsBar.tsx
  • web/src/pages/org/DepartmentGroupNode.tsx
  • web/src/pages/org/NodeContextMenu.tsx
  • web/src/pages/org/OrgChartToolbar.tsx
  • web/src/__tests__/pages/org/layout.test.ts
  • web/src/__tests__/pages/org/NodeContextMenu.test.tsx
  • web/src/pages/org/CeoNode.stories.tsx
  • web/src/pages/org/AgentNode.tsx
  • web/src/pages/org/AgentNode.stories.tsx
  • web/src/__tests__/pages/org/build-org-tree.test.ts
  • web/src/pages/org/DepartmentStatsBar.stories.tsx
  • web/src/pages/org/build-org-tree.ts
  • web/src/stores/company.ts
web/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

web/src/**/*.{ts,tsx}: Use React 19 with TypeScript 6+ in web dashboard; enforce design tokens (no hardcoded colors, fonts, spacing) and reuse components from web/src/components/ui/
Always reuse existing components from web/src/components/ui/ (StatusBadge, MetricCard, Sparkline, SectionCard, AgentCard, DeptHealthBar, ProgressGauge, StatPill, Avatar, Button, Toast, Skeleton, EmptyState, ErrorBoundary, ConfirmDialog, CommandPalette, InlineEdit, AnimatedPresence, StaggerGroup/StaggerItem) before creating new ones
Use design tokens exclusively in web components: Tailwind semantic classes (text-foreground, bg-card, text-accent, text-success, bg-danger, etc.) or CSS variables (var(--so-accent)); never hardcode hex values or pixel spacing
Use font-sans or font-mono (Geist tokens) in web components; never set fontFamily directly
Use density-aware spacing tokens in web components (p-card, gap-section-gap, gap-grid-gap) or standard Tailwind spacing; never hardcode pixel values for layout spacing
Use shadow and border token variables in web components (var(--so-shadow-card-hover), border-border, border-bright); never hardcode shadow or border styles
In React components, import cn from @/lib/utils for conditional class merging; never concatenate class strings directly
Do not recreate status dots inline; use <StatusBadge> component
Do not build card-with-header layouts from scratch; use <SectionCard> component
Do not create metric displays with text-metric font-bold; use <MetricCard> component
Do not render initials circles manually; use <Avatar> component
Do not create complex (>8 line) JSX inside .map() blocks; extract to a shared component

Files:

  • web/src/__tests__/pages/org/OrgChartToolbar.test.tsx
  • web/src/pages/org/OrgChartSkeleton.tsx
  • web/src/__tests__/stores/agents.test.ts
  • web/src/pages/org/OrgChartToolbar.stories.tsx
  • web/src/__tests__/pages/org/OrgChartSkeleton.test.tsx
  • web/src/pages/org/OrgChartSkeleton.stories.tsx
  • web/src/pages/org/status-mapping.ts
  • web/src/pages/org/HierarchyEdge.tsx
  • web/src/pages/org/DepartmentGroupNode.stories.tsx
  • web/src/__tests__/pages/org/DepartmentStatsBar.test.tsx
  • web/src/pages/org/CeoNode.tsx
  • web/src/__tests__/pages/org/OrgChartPage.test.tsx
  • web/src/__tests__/pages/org/status-mapping.test.ts
  • web/src/pages/OrgChartPage.tsx
  • web/src/hooks/useOrgChartData.ts
  • web/src/__tests__/stores/company.test.ts
  • web/src/stores/agents.ts
  • web/src/pages/org/NodeContextMenu.stories.tsx
  • web/src/pages/org/layout.ts
  • web/src/pages/org/DepartmentStatsBar.tsx
  • web/src/pages/org/DepartmentGroupNode.tsx
  • web/src/pages/org/NodeContextMenu.tsx
  • web/src/pages/org/OrgChartToolbar.tsx
  • web/src/__tests__/pages/org/layout.test.ts
  • web/src/__tests__/pages/org/NodeContextMenu.test.tsx
  • web/src/pages/org/CeoNode.stories.tsx
  • web/src/pages/org/AgentNode.tsx
  • web/src/pages/org/AgentNode.stories.tsx
  • web/src/__tests__/pages/org/build-org-tree.test.ts
  • web/src/pages/org/DepartmentStatsBar.stories.tsx
  • web/src/pages/org/build-org-tree.ts
  • web/src/stores/company.ts
web/src/__tests__/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

web/src/__tests__/**/*.{ts,tsx}: Use fast-check for property-based testing in React; use fc.assert and fc.property
Use Vitest for React unit testing with coverage scoped to files changed vs origin/main

Files:

  • web/src/__tests__/pages/org/OrgChartToolbar.test.tsx
  • web/src/__tests__/stores/agents.test.ts
  • web/src/__tests__/pages/org/OrgChartSkeleton.test.tsx
  • web/src/__tests__/pages/org/DepartmentStatsBar.test.tsx
  • web/src/__tests__/pages/org/OrgChartPage.test.tsx
  • web/src/__tests__/pages/org/status-mapping.test.ts
  • web/src/__tests__/stores/company.test.ts
  • web/src/__tests__/pages/org/layout.test.ts
  • web/src/__tests__/pages/org/NodeContextMenu.test.tsx
  • web/src/__tests__/pages/org/build-org-tree.test.ts
web/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use ESLint with @eslint-react/eslint-plugin and eslint-plugin-security in web dashboard

Files:

  • web/src/__tests__/pages/org/OrgChartToolbar.test.tsx
  • web/src/pages/org/OrgChartSkeleton.tsx
  • web/src/__tests__/stores/agents.test.ts
  • web/src/pages/org/OrgChartToolbar.stories.tsx
  • web/src/__tests__/pages/org/OrgChartSkeleton.test.tsx
  • web/src/pages/org/OrgChartSkeleton.stories.tsx
  • web/src/pages/org/status-mapping.ts
  • web/src/pages/org/HierarchyEdge.tsx
  • web/src/pages/org/DepartmentGroupNode.stories.tsx
  • web/src/__tests__/pages/org/DepartmentStatsBar.test.tsx
  • web/src/pages/org/CeoNode.tsx
  • web/src/__tests__/pages/org/OrgChartPage.test.tsx
  • web/src/__tests__/pages/org/status-mapping.test.ts
  • web/src/pages/OrgChartPage.tsx
  • web/src/hooks/useOrgChartData.ts
  • web/src/__tests__/stores/company.test.ts
  • web/src/stores/agents.ts
  • web/src/pages/org/NodeContextMenu.stories.tsx
  • web/src/pages/org/layout.ts
  • web/src/pages/org/DepartmentStatsBar.tsx
  • web/src/pages/org/DepartmentGroupNode.tsx
  • web/src/pages/org/NodeContextMenu.tsx
  • web/src/pages/org/OrgChartToolbar.tsx
  • web/src/__tests__/pages/org/layout.test.ts
  • web/src/__tests__/pages/org/NodeContextMenu.test.tsx
  • web/src/pages/org/CeoNode.stories.tsx
  • web/src/pages/org/AgentNode.tsx
  • web/src/pages/org/AgentNode.stories.tsx
  • web/src/__tests__/pages/org/build-org-tree.test.ts
  • web/src/pages/org/DepartmentStatsBar.stories.tsx
  • web/src/pages/org/build-org-tree.ts
  • web/src/stores/company.ts
web/**

📄 CodeRabbit inference engine (CLAUDE.md)

Use Node.js 22+ and npm for web dashboard; all dependencies in web/package.json (React 19, react-router, shadcn/ui, Radix UI, Tailwind CSS 4, Zustand, Recharts, Framer Motion, Axios, Lucide React, Geist fonts, Storybook 10, Vitest, ESLint, fast-check, etc.)

Files:

  • web/src/__tests__/pages/org/OrgChartToolbar.test.tsx
  • web/src/styles/global.css
  • web/package.json
  • web/src/pages/org/OrgChartSkeleton.tsx
  • web/src/__tests__/stores/agents.test.ts
  • web/src/pages/org/OrgChartToolbar.stories.tsx
  • web/src/__tests__/pages/org/OrgChartSkeleton.test.tsx
  • web/src/pages/org/OrgChartSkeleton.stories.tsx
  • web/src/pages/org/status-mapping.ts
  • web/src/pages/org/HierarchyEdge.tsx
  • web/src/pages/org/DepartmentGroupNode.stories.tsx
  • web/src/__tests__/pages/org/DepartmentStatsBar.test.tsx
  • web/src/pages/org/CeoNode.tsx
  • web/src/__tests__/pages/org/OrgChartPage.test.tsx
  • web/src/__tests__/pages/org/status-mapping.test.ts
  • web/src/pages/OrgChartPage.tsx
  • web/src/hooks/useOrgChartData.ts
  • web/src/__tests__/stores/company.test.ts
  • web/src/stores/agents.ts
  • web/src/pages/org/NodeContextMenu.stories.tsx
  • web/src/pages/org/layout.ts
  • web/src/pages/org/DepartmentStatsBar.tsx
  • web/src/pages/org/DepartmentGroupNode.tsx
  • web/src/pages/org/NodeContextMenu.tsx
  • web/src/pages/org/OrgChartToolbar.tsx
  • web/src/__tests__/pages/org/layout.test.ts
  • web/src/__tests__/pages/org/NodeContextMenu.test.tsx
  • web/src/pages/org/CeoNode.stories.tsx
  • web/src/pages/org/AgentNode.tsx
  • web/src/pages/org/AgentNode.stories.tsx
  • web/src/__tests__/pages/org/build-org-tree.test.ts
  • web/src/pages/org/DepartmentStatsBar.stories.tsx
  • web/src/pages/org/build-org-tree.ts
  • web/src/stores/company.ts
web/src/pages/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use React Router with lazy-loaded page components (one per route); place page-scoped sub-components in pages/<page-name>/ subdirectories

Files:

  • web/src/pages/org/OrgChartSkeleton.tsx
  • web/src/pages/org/OrgChartToolbar.stories.tsx
  • web/src/pages/org/OrgChartSkeleton.stories.tsx
  • web/src/pages/org/status-mapping.ts
  • web/src/pages/org/HierarchyEdge.tsx
  • web/src/pages/org/DepartmentGroupNode.stories.tsx
  • web/src/pages/org/CeoNode.tsx
  • web/src/pages/OrgChartPage.tsx
  • web/src/pages/org/NodeContextMenu.stories.tsx
  • web/src/pages/org/layout.ts
  • web/src/pages/org/DepartmentStatsBar.tsx
  • web/src/pages/org/DepartmentGroupNode.tsx
  • web/src/pages/org/NodeContextMenu.tsx
  • web/src/pages/org/OrgChartToolbar.tsx
  • web/src/pages/org/CeoNode.stories.tsx
  • web/src/pages/org/AgentNode.tsx
  • web/src/pages/org/AgentNode.stories.tsx
  • web/src/pages/org/DepartmentStatsBar.stories.tsx
  • web/src/pages/org/build-org-tree.ts
web/**/*.stories.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

web/**/*.stories.{ts,tsx}: In Storybook, use parameters.backgrounds.options (object keyed by name) and initialGlobals.backgrounds.value for background configuration
In Storybook, use parameters.a11y.test: 'error' | 'todo' | 'off' for a11y testing configuration (replaces old .element and .manual)

Files:

  • web/src/pages/org/OrgChartToolbar.stories.tsx
  • web/src/pages/org/OrgChartSkeleton.stories.tsx
  • web/src/pages/org/DepartmentGroupNode.stories.tsx
  • web/src/pages/org/NodeContextMenu.stories.tsx
  • web/src/pages/org/CeoNode.stories.tsx
  • web/src/pages/org/AgentNode.stories.tsx
  • web/src/pages/org/DepartmentStatsBar.stories.tsx
web/src/stores/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use Zustand stores in web dashboard for state management (auth, WebSocket, toast, analytics, domain shells)

Files:

  • web/src/stores/agents.ts
  • web/src/stores/company.ts
🧠 Learnings (28)
📓 Common learnings
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/).
📚 Learning: 2026-03-27T09:44:40.059Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T09:44:40.059Z
Learning: Applies to web/src/__tests__/**/*.{ts,tsx} : Use Vitest for React unit testing with coverage scoped to files changed vs origin/main

Applied to files:

  • web/src/__tests__/pages/org/OrgChartToolbar.test.tsx
  • web/src/__tests__/stores/agents.test.ts
  • web/src/__tests__/pages/org/OrgChartSkeleton.test.tsx
  • web/src/__tests__/pages/org/DepartmentStatsBar.test.tsx
  • web/src/__tests__/pages/org/OrgChartPage.test.tsx
  • web/src/__tests__/pages/org/status-mapping.test.ts
  • web/src/__tests__/stores/company.test.ts
  • web/src/__tests__/pages/org/layout.test.ts
  • web/src/__tests__/pages/org/NodeContextMenu.test.tsx
  • web/src/__tests__/pages/org/build-org-tree.test.ts
📚 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/src/__tests__/pages/org/OrgChartToolbar.test.tsx
  • web/src/__tests__/stores/agents.test.ts
  • web/src/__tests__/pages/org/OrgChartSkeleton.test.tsx
  • web/src/__tests__/pages/org/DepartmentStatsBar.test.tsx
  • web/src/__tests__/pages/org/OrgChartPage.test.tsx
  • web/src/__tests__/pages/org/status-mapping.test.ts
  • CLAUDE.md
  • web/src/__tests__/stores/company.test.ts
  • web/src/__tests__/pages/org/layout.test.ts
  • web/src/__tests__/pages/org/NodeContextMenu.test.tsx
  • web/src/__tests__/pages/org/build-org-tree.test.ts
📚 Learning: 2026-03-27T09:44:40.059Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T09:44:40.059Z
Learning: Applies to web/src/__tests__/**/*.{ts,tsx} : Use fast-check for property-based testing in React; use `fc.assert` and `fc.property`

Applied to files:

  • web/src/__tests__/pages/org/OrgChartToolbar.test.tsx
  • web/src/__tests__/pages/org/OrgChartSkeleton.test.tsx
  • web/src/__tests__/pages/org/DepartmentStatsBar.test.tsx
  • web/src/__tests__/pages/org/OrgChartPage.test.tsx
  • web/src/__tests__/stores/company.test.ts
  • web/src/__tests__/pages/org/layout.test.ts
  • web/src/__tests__/pages/org/NodeContextMenu.test.tsx
  • web/src/__tests__/pages/org/build-org-tree.test.ts
📚 Learning: 2026-03-27T09:44:40.059Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T09:44:40.059Z
Learning: Applies to web/src/components/**/*.stories.{ts,tsx} : Use Storybook 10 (ESM-only) for React component documentation; import from `storybook/test`, `storybook/actions`; use `definePreview` from `storybook/react-vite`

Applied to files:

  • web/src/__tests__/pages/org/OrgChartToolbar.test.tsx
  • web/package.json
  • web/src/pages/org/OrgChartToolbar.stories.tsx
  • web/src/pages/org/OrgChartSkeleton.stories.tsx
  • web/src/pages/org/DepartmentGroupNode.stories.tsx
  • web/src/__tests__/stores/company.test.ts
  • web/src/pages/org/NodeContextMenu.stories.tsx
  • web/src/pages/org/CeoNode.stories.tsx
  • web/src/pages/org/AgentNode.stories.tsx
  • web/src/pages/org/DepartmentStatsBar.stories.tsx
📚 Learning: 2026-03-27T09:44:40.059Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T09:44:40.059Z
Learning: Applies to web/**/*.stories.{ts,tsx} : In Storybook, use `parameters.a11y.test: 'error' | 'todo' | 'off'` for a11y testing configuration (replaces old `.element` and `.manual`)

Applied to files:

  • web/src/__tests__/pages/org/OrgChartToolbar.test.tsx
  • web/src/pages/org/OrgChartToolbar.stories.tsx
  • web/src/__tests__/pages/org/OrgChartSkeleton.test.tsx
  • web/src/pages/org/OrgChartSkeleton.stories.tsx
  • web/src/pages/org/DepartmentGroupNode.stories.tsx
  • web/src/pages/org/NodeContextMenu.stories.tsx
  • web/src/pages/org/CeoNode.stories.tsx
  • web/src/pages/org/AgentNode.stories.tsx
  • web/src/pages/org/DepartmentStatsBar.stories.tsx
📚 Learning: 2026-03-27T09:44:40.059Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T09:44:40.059Z
Learning: Applies to web/src/**/*.{ts,tsx} : In React components, import `cn` from `@/lib/utils` for conditional class merging; never concatenate class strings directly

Applied to files:

  • web/src/styles/global.css
📚 Learning: 2026-03-27T09:44:40.059Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T09:44:40.059Z
Learning: Applies to web/src/**/*.{ts,tsx} : Use React 19 with TypeScript 6+ in web dashboard; enforce design tokens (no hardcoded colors, fonts, spacing) and reuse components from `web/src/components/ui/`

Applied to files:

  • web/src/styles/global.css
  • web/package.json
  • web/src/pages/org/OrgChartSkeleton.tsx
  • web/src/pages/org/HierarchyEdge.tsx
  • web/src/pages/org/CeoNode.tsx
  • web/src/pages/OrgChartPage.tsx
  • CLAUDE.md
  • web/src/hooks/useOrgChartData.ts
  • web/src/pages/org/layout.ts
  • web/src/pages/org/DepartmentStatsBar.tsx
  • web/src/pages/org/DepartmentGroupNode.tsx
  • web/src/pages/org/OrgChartToolbar.tsx
  • web/src/pages/org/AgentNode.tsx
  • web/src/pages/org/build-org-tree.ts
📚 Learning: 2026-03-27T09:44:40.059Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T09:44:40.059Z
Learning: Applies to web/src/**/*.{ts,tsx} : Use shadow and border token variables in web components (`var(--so-shadow-card-hover)`, `border-border`, `border-bright`); never hardcode shadow or border styles

Applied to files:

  • web/src/styles/global.css
📚 Learning: 2026-03-27T09:44:40.059Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T09:44:40.059Z
Learning: Applies to web/src/**/*.{ts,tsx} : Use `font-sans` or `font-mono` (Geist tokens) in web components; never set `fontFamily` directly

Applied to files:

  • web/src/styles/global.css
📚 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
  • CLAUDE.md
📚 Learning: 2026-03-27T09:44:40.059Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T09:44:40.059Z
Learning: Applies to web/** : Use Node.js 22+ and npm for web dashboard; all dependencies in `web/package.json` (React 19, react-router, shadcn/ui, Radix UI, Tailwind CSS 4, Zustand, Recharts, Framer Motion, Axios, Lucide React, Geist fonts, Storybook 10, Vitest, ESLint, fast-check, etc.)

Applied to files:

  • web/package.json
  • 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: 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:

  • web/package.json
  • CLAUDE.md
📚 Learning: 2026-03-27T09:44:40.059Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T09:44:40.059Z
Learning: Applies to web/.storybook/**/*.{ts,tsx} : In Storybook, use type-safe config with `defineMain` from `storybook/react-vite/node` and `definePreview` from `storybook/react-vite`; include explicit `framework` field

Applied to files:

  • web/package.json
  • web/src/pages/org/OrgChartToolbar.stories.tsx
  • web/src/pages/org/OrgChartSkeleton.stories.tsx
  • web/src/pages/org/DepartmentGroupNode.stories.tsx
  • web/src/pages/org/NodeContextMenu.stories.tsx
  • web/src/pages/org/CeoNode.stories.tsx
  • web/src/pages/org/AgentNode.stories.tsx
  • web/src/pages/org/DepartmentStatsBar.stories.tsx
📚 Learning: 2026-03-27T09:44:40.059Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T09:44:40.059Z
Learning: Applies to web/src/**/*.{ts,tsx} : Always reuse existing components from `web/src/components/ui/` (StatusBadge, MetricCard, Sparkline, SectionCard, AgentCard, DeptHealthBar, ProgressGauge, StatPill, Avatar, Button, Toast, Skeleton, EmptyState, ErrorBoundary, ConfirmDialog, CommandPalette, InlineEdit, AnimatedPresence, StaggerGroup/StaggerItem) before creating new ones

Applied to files:

  • web/src/pages/org/OrgChartSkeleton.tsx
  • web/src/pages/org/HierarchyEdge.tsx
  • web/src/pages/org/DepartmentGroupNode.stories.tsx
  • web/src/__tests__/pages/org/DepartmentStatsBar.test.tsx
  • web/src/pages/org/CeoNode.tsx
  • web/src/hooks/useOrgChartData.ts
  • web/src/pages/org/DepartmentStatsBar.tsx
  • web/src/pages/org/DepartmentGroupNode.tsx
  • web/src/pages/org/AgentNode.tsx
  • web/src/pages/org/DepartmentStatsBar.stories.tsx
📚 Learning: 2026-03-27T09:44:40.059Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T09:44:40.059Z
Learning: Applies to web/src/components/ui/**/*.{ts,tsx} : When creating new shared React components, place them in `web/src/components/ui/` with kebab-case filename, create accompanying `.stories.tsx` Storybook file with all states, export TypeScript interface for props, and use design tokens exclusively

Applied to files:

  • web/src/pages/org/OrgChartSkeleton.tsx
  • web/src/pages/org/OrgChartToolbar.stories.tsx
  • web/src/pages/org/OrgChartSkeleton.stories.tsx
  • web/src/pages/org/DepartmentGroupNode.stories.tsx
  • web/src/pages/org/CeoNode.tsx
  • CLAUDE.md
  • web/src/pages/org/NodeContextMenu.stories.tsx
  • web/src/pages/org/DepartmentStatsBar.tsx
  • web/src/pages/org/DepartmentGroupNode.tsx
  • web/src/pages/org/CeoNode.stories.tsx
  • web/src/pages/org/AgentNode.stories.tsx
  • web/src/pages/org/DepartmentStatsBar.stories.tsx
📚 Learning: 2026-03-27T09:44:40.059Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T09:44:40.059Z
Learning: Applies to web/src/**/*.{ts,tsx} : Do not build card-with-header layouts from scratch; use `<SectionCard>` component

Applied to files:

  • web/src/pages/org/OrgChartSkeleton.tsx
  • web/src/pages/org/layout.ts
  • web/src/pages/org/DepartmentGroupNode.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/org/OrgChartSkeleton.tsx
  • web/src/pages/OrgChartPage.tsx
  • CLAUDE.md
  • web/src/pages/org/DepartmentStatsBar.tsx
  • web/src/pages/org/DepartmentStatsBar.stories.tsx
  • web/src/pages/org/build-org-tree.ts
📚 Learning: 2026-03-27T09:44:40.059Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T09:44:40.059Z
Learning: Applies to web/src/**/*.{ts,tsx} : Do not create complex (>8 line) JSX inside `.map()` blocks; extract to a shared component

Applied to files:

  • web/src/pages/org/OrgChartSkeleton.tsx
📚 Learning: 2026-03-27T09:44:40.059Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T09:44:40.059Z
Learning: Applies to web/src/stores/**/*.{ts,tsx} : Use Zustand stores in web dashboard for state management (auth, WebSocket, toast, analytics, domain shells)

Applied to files:

  • web/src/__tests__/stores/agents.test.ts
  • CLAUDE.md
  • web/src/__tests__/stores/company.test.ts
  • web/src/stores/agents.ts
  • web/src/stores/company.ts
📚 Learning: 2026-03-27T09:44:40.059Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T09:44:40.059Z
Learning: Applies to web/.storybook/preview.tsx : In Storybook, set a11y testing globally in `preview.tsx` with `parameters.a11y.test: 'error'` to enforce WCAG compliance on all stories

Applied to files:

  • web/src/pages/org/OrgChartToolbar.stories.tsx
  • web/src/__tests__/pages/org/OrgChartSkeleton.test.tsx
📚 Learning: 2026-03-27T09:44:40.059Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T09:44:40.059Z
Learning: Applies to web/**/*.stories.{ts,tsx} : In Storybook, use `parameters.backgrounds.options` (object keyed by name) and `initialGlobals.backgrounds.value` for background configuration

Applied to files:

  • web/src/pages/org/OrgChartSkeleton.stories.tsx
  • web/src/pages/org/DepartmentGroupNode.stories.tsx
  • web/src/pages/org/NodeContextMenu.stories.tsx
  • web/src/pages/org/DepartmentStatsBar.stories.tsx
📚 Learning: 2026-03-19T07:13:44.964Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:13:44.964Z
Learning: Applies to src/synthorg/hr/**/*.py : HR package (hr/): hiring, firing, onboarding, offboarding, agent registry, performance tracking (task metrics, collaboration scoring, LLM calibration, collaboration overrides, trend detection), promotion/demotion (criteria evaluation, approval strategies, model mapping)

Applied to files:

  • web/src/pages/org/status-mapping.ts
📚 Learning: 2026-03-27T09:44:40.059Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T09:44:40.059Z
Learning: Applies to web/src/**/*.{ts,tsx} : Do not render initials circles manually; use `<Avatar>` component

Applied to files:

  • web/src/pages/org/CeoNode.tsx
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to src/synthorg/**/*.py : Package structure: src/synthorg/ organized as: api/ (REST+WebSocket, Litestar), auth/ (auth subpackage), backup/ (scheduled/manual backups), budget/ (cost tracking, CFO), cli/ (superseded by Go CLI), communication/ (message bus, meetings), config/ (YAML loading), core/ (domain models, resilience config), engine/ (orchestration, task state, coordination, approval gates, stagnation detection, context budget, compaction), hr/ (hiring, performance, promotion), memory/ (pluggable backend, Mem0, retrieval, consolidation), persistence/ (operational data, SQLite, settings), observability/ (logging, correlation, sinks), providers/ (LLM abstraction, LiteLLM, auth types, presets, runtime CRUD), settings/ (runtime-editable, typed definitions, encryption, config bridge), security/ (SecOps, rule engine, output scanning, progressive trust, autonomy levels), templates/ (company templates, personalities), tools/ (registry, built-in tools, git, sandbox, code_runner, MCP...

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-27T09:44:40.059Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T09:44:40.059Z
Learning: Applies to web/src/pages/**/*.{ts,tsx} : Use React Router with lazy-loaded page components (one per route); place page-scoped sub-components in `pages/<page-name>/` subdirectories

Applied to files:

  • CLAUDE.md
  • web/src/pages/org/layout.ts
📚 Learning: 2026-03-27T09:44:40.059Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T09:44:40.059Z
Learning: Applies to web/src/**/*.{ts,tsx} : Do not recreate status dots inline; use `<StatusBadge>` component

Applied to files:

  • web/src/pages/org/DepartmentStatsBar.tsx
  • web/src/pages/org/AgentNode.tsx
📚 Learning: 2026-03-27T09:44:40.059Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T09:44:40.059Z
Learning: Applies to web/src/**/*.{ts,tsx} : Do not create metric displays with `text-metric font-bold`; use `<MetricCard>` component

Applied to files:

  • web/src/pages/org/DepartmentStatsBar.tsx
🔇 Additional comments (24)
web/src/styles/global.css (1)

7-7: React Flow base stylesheet import is correctly placed.

No issues with this addition.

web/src/pages/org/OrgChartSkeleton.tsx (1)

1-30: Good skeleton implementation with accessible loading semantics.

Shared UI reuse and status-region attributes are in place.

web/src/pages/org/HierarchyEdge.tsx (1)

1-27: Hierarchy edge renderer looks correct and cohesive with the graph setup.

No issues found in this segment.

web/src/pages/org/DepartmentStatsBar.stories.tsx (1)

1-45: Story coverage is solid for key DepartmentStatsBar states.

No concerns in this segment.

web/package.json (1)

18-52: No actionable concerns in this dependency diff.

web/src/__tests__/pages/org/DepartmentStatsBar.test.tsx (1)

6-40: Solid coverage for core render states.

This test suite cleanly covers count rendering, cost conditionality, and test-id presence for the component surface changed in this PR.

web/src/__tests__/pages/org/OrgChartSkeleton.test.tsx (1)

5-20: Nice a11y assertions for loading state.

These checks validate status semantics and announcement behavior well for the skeleton component.

CLAUDE.md (1)

127-132: Documentation update is clear and aligned with the implementation.

The hooks/stores tree comments now accurately reflect the new org-chart data composition and Zustand domains.

web/src/__tests__/pages/org/status-mapping.test.ts (1)

22-43: Good precedence coverage for runtime-vs-HR conflicts.

These cases exercise the critical override semantics and edge conditions clearly.

web/src/pages/org/OrgChartToolbar.stories.tsx (1)

18-22: > Likely an incorrect or invalid review comment.

web/src/__tests__/stores/agents.test.ts (1)

1-82: LGTM! Well-structured test coverage for the agents store.

The test suite provides comprehensive coverage for both updateRuntimeStatus and updateFromWsEvent, including proper validation of edge cases (missing fields, invalid status values, wrong event types). The beforeEach reset ensures test isolation.

web/src/pages/org/CeoNode.tsx (1)

1-52: Well-implemented CEO node with proper design token usage.

The component correctly reuses Avatar and StatusBadge from the shared UI library, uses semantic design tokens throughout, and includes proper accessibility attributes (aria-label, data-testid). The memoization is appropriate for React Flow node performance.

web/src/pages/org/DepartmentGroupNode.tsx (1)

1-51: LGTM! Clean implementation with proper design tokens and accessibility.

The component correctly uses semantic color tokens for health-based styling, includes DepartmentStatsBar for stats display, and provides proper accessibility attributes. The fallback on line 18 is defensive (unreachable given getHealthColor always returns a valid key), which is acceptable.

web/src/pages/org/AgentNode.stories.tsx (1)

34-66: Good coverage of all runtime status states.

The stories provide complete coverage of all AgentRuntimeStatus values (active, idle, error, offline). The Wrapper pattern with disabled interactions is appropriate for static Storybook previews.

web/src/__tests__/pages/org/layout.test.ts (1)

1-104: Good test coverage for the layout utility.

The test suite covers key layout scenarios including empty input, position assignment, sibling separation, directional layout, department grouping, and edge case handling (missing nodes). The helper functions makeNode and makeEdge keep tests readable.

web/src/pages/org/DepartmentGroupNode.stories.tsx (1)

44-84: LGTM — good coverage of health states.

The three stories (Healthy, Warning, Critical) provide useful visual documentation for different department health scenarios, including the costUsd: null edge case in Critical.

web/src/__tests__/pages/org/NodeContextMenu.test.tsx (1)

13-60: LGTM — comprehensive menu behavior coverage.

Tests cover the key scenarios: conditional rendering based on node type, callback invocation with correct arguments, keyboard accessibility (Escape), and ARIA roles.

web/src/__tests__/pages/org/OrgChartPage.test.tsx (1)

1-143: LGTM — solid page-level test coverage.

The test suite effectively covers all major UI states (loading, empty, error, WebSocket disconnect) with proper mock isolation via beforeEach. The module-level mock state pattern is appropriate for Vitest.

web/src/pages/OrgChartPage.tsx (2)

267-286: LGTM — clean page structure with proper error boundaries.

The page layout correctly wraps the ReactFlow canvas in ReactFlowProvider and ErrorBoundary, with a clear header section containing navigation.


234-237: No Pro license required for hideAttribution.

The hideAttribution option in proOptions is available to all React Flow users under the MIT license and does not require a Pro subscription. While a Pro subscription is appreciated for supporting the project, it is not a prerequisite for hiding the attribution.

			> Likely an incorrect or invalid review comment.
web/src/stores/agents.ts (1)

1-39: LGTM — well-structured store with proper validation.

The store correctly validates WebSocket payloads before updating state, and the VALID_RUNTIME_STATUSES Set matches the AgentRuntimeStatus type definition. Immutable state updates using spread operator are correct.

web/src/hooks/useOrgChartData.ts (1)

68-74: LGTM — efficient memoization of derived graph data.

The useMemo correctly depends on config, runtimeStatuses, and departmentHealths, ensuring the graph is only rebuilt when source data changes.

web/src/__tests__/stores/company.test.ts (1)

1-119: LGTM — comprehensive store test coverage.

The test suite properly covers initial state, successful/failed API calls, and WebSocket event handling. The vi.waitFor pattern correctly handles async assertions for the re-fetch behavior.

web/src/__tests__/pages/org/build-org-tree.test.ts (1)

66-309: LGTM — thorough coverage of org tree construction logic.

The test suite comprehensively validates CEO selection priority, department grouping, hierarchy edges, terminated agent exclusion, health data integration, and edge deduplication. Good use of helper functions for test data setup.

Comment on lines +284 to +294
it('includes companyName in CEO node data', () => {
const agents = [
makeAgent({ id: 'ceo', name: 'Boss', department: 'executive', level: 'c_suite' }),
]
const config = makeConfig(agents)
config.company_name = 'Acme Inc'
const result = buildOrgTree({ ...config, company_name: 'Acme Inc' }, {}, [])

const ceoNode = result.nodes.find((n) => n.type === 'ceo')
expect(ceoNode!.data.companyName).toBe('Acme Inc')
})
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Remove redundant company_name assignment.

Line 289 assigns config.company_name = 'Acme Inc', then line 290 spreads it with the same value again. The mutation is sufficient.

♻️ Suggested fix
   it('includes companyName in CEO node data', () => {
     const agents = [
       makeAgent({ id: 'ceo', name: 'Boss', department: 'executive', level: 'c_suite' }),
     ]
     const config = makeConfig(agents)
     config.company_name = 'Acme Inc'
-    const result = buildOrgTree({ ...config, company_name: 'Acme Inc' }, {}, [])
+    const result = buildOrgTree(config, {}, [])

     const ceoNode = result.nodes.find((n) => n.type === 'ceo')
     expect(ceoNode!.data.companyName).toBe('Acme Inc')
   })
📝 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.

Suggested change
it('includes companyName in CEO node data', () => {
const agents = [
makeAgent({ id: 'ceo', name: 'Boss', department: 'executive', level: 'c_suite' }),
]
const config = makeConfig(agents)
config.company_name = 'Acme Inc'
const result = buildOrgTree({ ...config, company_name: 'Acme Inc' }, {}, [])
const ceoNode = result.nodes.find((n) => n.type === 'ceo')
expect(ceoNode!.data.companyName).toBe('Acme Inc')
})
it('includes companyName in CEO node data', () => {
const agents = [
makeAgent({ id: 'ceo', name: 'Boss', department: 'executive', level: 'c_suite' }),
]
const config = makeConfig(agents)
config.company_name = 'Acme Inc'
const result = buildOrgTree(config, {}, [])
const ceoNode = result.nodes.find((n) => n.type === 'ceo')
expect(ceoNode!.data.companyName).toBe('Acme Inc')
})
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/__tests__/pages/org/build-org-tree.test.ts` around lines 284 - 294,
The test mutates config.company_name and then passes a spread with the same
value to buildOrgTree, which is redundant; remove the standalone assignment
config.company_name = 'Acme Inc' and keep only the spread when calling
buildOrgTree (refer to makeConfig, config, and buildOrgTree in the "includes
companyName in CEO node data" test) so the test sets company_name exactly once
without mutation.

Comment on lines +45 to +49
useEffect(() => {
polling.start()
return () => polling.stop()
// eslint-disable-next-line @eslint-react/exhaustive-deps
}, [])
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check which exhaustive-deps rule is configured in the project
rg -n "exhaustive-deps" --type=json --type=js --type=ts -g "*.config.*" -g ".eslintrc*"

Repository: Aureliolo/synthorg

Length of output: 44


🏁 Script executed:

#!/bin/bash
# Find ESLint config files
fd -e "eslintrc*" -e "eslint.config.*" . web/

# Also check web/package.json for ESLint plugins
echo "=== ESLint plugins in web/package.json ==="
grep -A 5 -B 5 "eslint" web/package.json | head -50

Repository: Aureliolo/synthorg

Length of output: 1235


🏁 Script executed:

#!/bin/bash
# Find ESLint config file
fd -type f "eslint.config.*" . web/

# Also check if there's a legacy .eslintrc
ls -la web/.eslintrc* 2>/dev/null || echo "No legacy .eslintrc found"

Repository: Aureliolo/synthorg

Length of output: 275


🌐 Web query:

@eslint-react/eslint-plugin exhaustive-deps rule

💡 Result:

@eslint-react/eslint-plugin is a modern, performant ESLint plugin for React (4-7x faster than alternatives), providing composable rules for React, TypeScript, React 19+, Server Components, and more. It does not have a rule named "exhaustive-deps". The "exhaustive-deps" rule originates from the official eslint-plugin-react-hooks package (from the React team), which validates dependency arrays in hooks like useEffect, useCallback, useMemo to prevent stale closures by ensuring all referenced values are included. It is enabled by default as a warning in the recommended config: "react-hooks/exhaustive-deps": "warn". @eslint-react/eslint-plugin focuses on different rules (e.g., no-missing-key, no-children-prop, jsx-aria, hooks/exhaustive-deps is absent from its rules list). For exhaustive-deps, use eslint-plugin-react-hooks alongside it if needed. Installation for @eslint-react/eslint-plugin: npm install --save-dev typescript-eslint @eslint-react/eslint-plugin Example eslint.config.js: import eslintReact from "@eslint-react/eslint-plugin"; export default [ eslintReact.configs["recommended-typescript"], // rules: { ... } ];

Citations:


Fix invalid ESLint rule name and missing plugin dependency.

The eslint-disable comment references @eslint-react/exhaustive-deps, but @eslint-react/eslint-plugin does not provide an exhaustive-deps rule. The exhaustive-deps rule comes from eslint-plugin-react-hooks (the official React team plugin), which is not installed in this project.

Either install eslint-plugin-react-hooks and update the disable comment to use the correct rule name react-hooks/exhaustive-deps, or remove the eslint-disable comment if exhaustive-deps checking is not desired. Currently, the comment has no effect since the rule doesn't exist in the configured plugins.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/hooks/useOrgChartData.ts` around lines 45 - 49, The ESLint disable is
referencing a non-existent rule name; update the hook to either install the
missing linter plugin `eslint-plugin-react-hooks` and change the comment to `//
eslint-disable-next-line react-hooks/exhaustive-deps` or remove the disable
entirely if you want the `useEffect` dependency check; locate the useEffect
where `polling.start()` / `polling.stop()` are called inside `useOrgChartData`
and apply the chosen change (add the plugin to devDependencies and enable it in
ESLint config if keeping the disable, or simply delete the incorrect `//
eslint-disable-next-line `@eslint-react/exhaustive-deps`` line).

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

♻️ Duplicate comments (1)
web/src/pages/org/layout.ts (1)

44-48: ⚠️ Potential issue | 🟠 Major

Dagre never sees real node dimensions here.

useOrgChartData() lays the graph out before React Flow mounts, and nothing passes measured nodes back into this utility, so node.measured is effectively always undefined here. Dagre therefore spaces the chart with the 160x80 fallbacks on every render, which is why wider CEO/department cards can still overlap or clip.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/pages/org/layout.ts` around lines 44 - 48, useOrgChartData currently
layouts the Dagre graph before React Flow mounts so node.measured is always
undefined causing DEFAULT_NODE_WIDTH/HEIGHT to be used; update the layout path
to consume real measured sizes: change useOrgChartData (or its caller) to accept
a measuredNodes map/prop (or a callback that supplies measured widths/heights)
and use those values when setting nodes in the loop that iterates leafNodes
(replace reliance on node.measured with the passed-in measurements), so
g.setNode(...) uses actual width/height instead of
DEFAULT_NODE_WIDTH/DEFAULT_NODE_HEIGHT and the Dagre layout will reflect real
card sizes.
🤖 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/__tests__/pages/org/NodeContextMenu.test.tsx`:
- Around line 1-2: The test file imports Vitest helpers but omitted beforeEach;
update the import from 'vitest' (where describe, expect, it, vi are imported) to
also import beforeEach so the beforeEach(...) call in NodeContextMenu.test.tsx
resolves at runtime; ensure the import statement that references describe,
expect, it, vi includes beforeEach.

In `@web/src/hooks/useOrgChartData.ts`:
- Around line 31-37: The effect currently calls companyStore.fetchCompanyData()
and companyStore.fetchDepartmentHealths() in parallel causing
fetchDepartmentHealths to early-return when store.config is null; change the
sequencing so fetchDepartmentHealths runs only after config is available — e.g.,
in the useEffect (or inside the Promise chain) await or .then() on
fetchCompanyData() (or observe useCompanyStore.getState().config) and only call
fetchDepartmentHealths() after that promise resolves and config is present;
update the useEffect that uses useCompanyStore.getState(), fetchCompanyData, and
fetchDepartmentHealths to ensure fetchDepartmentHealths is invoked after config
becomes non-null.

In `@web/src/pages/org/build-org-tree.ts`:
- Around line 124-133: teamMemberSet currently overwrites a member's parent if
their name appears in multiple dept.teams; update the loop in build-org-tree to
detect existing entries before setting: when iterating dept.teams and
teamMembers, check teamMemberSet.has(member.id) and either skip setting to avoid
overwrite or log a development-only warning (e.g., using console.warn or the
project logger) indicating the member appears in multiple teams, mentioning the
conflicting team and current teamLead; reference the symbols teamMemberSet,
dept.teams, deptMembers, findHighestSeniority, and team.members when making this
change so the duplicate-membership handling is applied where the map is
populated.
- Around line 226-233: The function findDepartmentHead creates an unnecessary
shallow copy with [...members] when ceo is null; since findHighestSeniority
accepts readonly AgentConfig[] you can pass members directly. Replace the
ternary that builds candidates in findDepartmentHead so it uses members (not
[...members]) when ceo is falsy, keeping the existing filter branch when ceo is
present and returning findHighestSeniority(candidates).

In `@web/src/pages/org/layout.ts`:
- Around line 74-78: The empty-group branch in the positionedGroups mapping
(inside groupNodes.map and the children.length === 0 check that uses
positionedLeafMap) currently sets every empty group to { x: 0, y: 0 }; change it
to compute a distinct layout slot per empty group instead of hard-coding the
origin — e.g., derive position from the group's index or maintain an emptyGroup
counter and place them on a grid (incrementing x/y by a fixed column/row size)
so each empty department gets its own non-overlapping coordinates while
preserving the style assignment.

In `@web/src/pages/OrgChartPage.tsx`:
- Around line 174-185: The handler handleViewModeChange currently calls
setViewMode(mode) for all ViewMode values including the unimplemented 'force';
change it so that when mode === 'force' you only call addToast(...) and return
without calling setViewMode, otherwise call setViewMode(mode); this preserves
the current selected view while still notifying the user (references:
handleViewModeChange, setViewMode, addToast, ViewMode, 'force').
- Around line 297-301: Replace the nested Link->Button pattern with the Button's
asChild composition: remove the outer <Link to={ROUTES.ORG_EDIT}> wrapper and
instead render <Button asChild size="sm" variant="outline"> with a <Link
to={ROUTES.ORG_EDIT}>Edit Organization</Link> as its child so the Button
delegates to the anchor element (preserving ROUTES.ORG_EDIT and Button props)
and avoids interactive element nesting.

---

Duplicate comments:
In `@web/src/pages/org/layout.ts`:
- Around line 44-48: useOrgChartData currently layouts the Dagre graph before
React Flow mounts so node.measured is always undefined causing
DEFAULT_NODE_WIDTH/HEIGHT to be used; update the layout path to consume real
measured sizes: change useOrgChartData (or its caller) to accept a measuredNodes
map/prop (or a callback that supplies measured widths/heights) and use those
values when setting nodes in the loop that iterates leafNodes (replace reliance
on node.measured with the passed-in measurements), so g.setNode(...) uses actual
width/height instead of DEFAULT_NODE_WIDTH/DEFAULT_NODE_HEIGHT and the Dagre
layout will reflect real card sizes.
🪄 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: 05462dce-9131-4f8f-89ff-a96cbdc6181c

📥 Commits

Reviewing files that changed from the base of the PR and between e199b1e and 6f095a1.

📒 Files selected for processing (26)
  • CLAUDE.md
  • web/src/__tests__/pages/org/DepartmentStatsBar.test.tsx
  • web/src/__tests__/pages/org/NodeContextMenu.test.tsx
  • web/src/__tests__/pages/org/OrgChartToolbar.test.tsx
  • web/src/__tests__/pages/org/build-org-tree.test.ts
  • web/src/__tests__/pages/org/layout.test.ts
  • web/src/__tests__/stores/company.test.ts
  • web/src/hooks/useOrgChartData.ts
  • web/src/pages/OrgChartPage.tsx
  • web/src/pages/org/AgentNode.stories.tsx
  • web/src/pages/org/AgentNode.tsx
  • web/src/pages/org/CeoNode.stories.tsx
  • web/src/pages/org/CeoNode.tsx
  • web/src/pages/org/DepartmentGroupNode.stories.tsx
  • web/src/pages/org/DepartmentGroupNode.tsx
  • web/src/pages/org/DepartmentStatsBar.stories.tsx
  • web/src/pages/org/DepartmentStatsBar.tsx
  • web/src/pages/org/NodeContextMenu.stories.tsx
  • web/src/pages/org/NodeContextMenu.tsx
  • web/src/pages/org/OrgChartSkeleton.stories.tsx
  • web/src/pages/org/OrgChartToolbar.stories.tsx
  • web/src/pages/org/OrgChartToolbar.tsx
  • web/src/pages/org/build-org-tree.ts
  • web/src/pages/org/layout.ts
  • web/src/pages/org/status-mapping.ts
  • web/src/stores/company.ts
📜 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 Backend
  • GitHub Check: Build Web
  • GitHub Check: Build Sandbox
  • GitHub Check: Dashboard Test
  • GitHub Check: Dependency Review
  • GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (8)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Use TypeScript 6+ with paths for module resolution (remove deprecated baseUrl); esModuleInterop is always true
In TypeScript, strict defaults to true and types defaults to []; do not auto-discover @types/* — must explicitly list needed types

Files:

  • web/src/pages/org/OrgChartSkeleton.stories.tsx
  • web/src/pages/org/status-mapping.ts
  • web/src/__tests__/pages/org/DepartmentStatsBar.test.tsx
  • web/src/__tests__/pages/org/OrgChartToolbar.test.tsx
  • web/src/pages/org/DepartmentGroupNode.tsx
  • web/src/__tests__/pages/org/layout.test.ts
  • web/src/pages/org/OrgChartToolbar.stories.tsx
  • web/src/__tests__/pages/org/NodeContextMenu.test.tsx
  • web/src/pages/org/DepartmentGroupNode.stories.tsx
  • web/src/pages/org/NodeContextMenu.tsx
  • web/src/pages/org/AgentNode.tsx
  • web/src/pages/org/DepartmentStatsBar.tsx
  • web/src/pages/org/CeoNode.tsx
  • web/src/pages/org/AgentNode.stories.tsx
  • web/src/stores/company.ts
  • web/src/pages/org/DepartmentStatsBar.stories.tsx
  • web/src/hooks/useOrgChartData.ts
  • web/src/__tests__/pages/org/build-org-tree.test.ts
  • web/src/pages/org/OrgChartToolbar.tsx
  • web/src/pages/org/NodeContextMenu.stories.tsx
  • web/src/pages/org/build-org-tree.ts
  • web/src/pages/org/CeoNode.stories.tsx
  • web/src/__tests__/stores/company.test.ts
  • web/src/pages/org/layout.ts
  • web/src/pages/OrgChartPage.tsx
web/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

web/src/**/*.{ts,tsx}: Use React 19 with TypeScript 6+ in web dashboard; enforce design tokens (no hardcoded colors, fonts, spacing) and reuse components from web/src/components/ui/
Always reuse existing components from web/src/components/ui/ (StatusBadge, MetricCard, Sparkline, SectionCard, AgentCard, DeptHealthBar, ProgressGauge, StatPill, Avatar, Button, Toast, Skeleton, EmptyState, ErrorBoundary, ConfirmDialog, CommandPalette, InlineEdit, AnimatedPresence, StaggerGroup/StaggerItem) before creating new ones
Use design tokens exclusively in web components: Tailwind semantic classes (text-foreground, bg-card, text-accent, text-success, bg-danger, etc.) or CSS variables (var(--so-accent)); never hardcode hex values or pixel spacing
Use font-sans or font-mono (Geist tokens) in web components; never set fontFamily directly
Use density-aware spacing tokens in web components (p-card, gap-section-gap, gap-grid-gap) or standard Tailwind spacing; never hardcode pixel values for layout spacing
Use shadow and border token variables in web components (var(--so-shadow-card-hover), border-border, border-bright); never hardcode shadow or border styles
In React components, import cn from @/lib/utils for conditional class merging; never concatenate class strings directly
Do not recreate status dots inline; use <StatusBadge> component
Do not build card-with-header layouts from scratch; use <SectionCard> component
Do not create metric displays with text-metric font-bold; use <MetricCard> component
Do not render initials circles manually; use <Avatar> component
Do not create complex (>8 line) JSX inside .map() blocks; extract to a shared component

Files:

  • web/src/pages/org/OrgChartSkeleton.stories.tsx
  • web/src/pages/org/status-mapping.ts
  • web/src/__tests__/pages/org/DepartmentStatsBar.test.tsx
  • web/src/__tests__/pages/org/OrgChartToolbar.test.tsx
  • web/src/pages/org/DepartmentGroupNode.tsx
  • web/src/__tests__/pages/org/layout.test.ts
  • web/src/pages/org/OrgChartToolbar.stories.tsx
  • web/src/__tests__/pages/org/NodeContextMenu.test.tsx
  • web/src/pages/org/DepartmentGroupNode.stories.tsx
  • web/src/pages/org/NodeContextMenu.tsx
  • web/src/pages/org/AgentNode.tsx
  • web/src/pages/org/DepartmentStatsBar.tsx
  • web/src/pages/org/CeoNode.tsx
  • web/src/pages/org/AgentNode.stories.tsx
  • web/src/stores/company.ts
  • web/src/pages/org/DepartmentStatsBar.stories.tsx
  • web/src/hooks/useOrgChartData.ts
  • web/src/__tests__/pages/org/build-org-tree.test.ts
  • web/src/pages/org/OrgChartToolbar.tsx
  • web/src/pages/org/NodeContextMenu.stories.tsx
  • web/src/pages/org/build-org-tree.ts
  • web/src/pages/org/CeoNode.stories.tsx
  • web/src/__tests__/stores/company.test.ts
  • web/src/pages/org/layout.ts
  • web/src/pages/OrgChartPage.tsx
web/src/pages/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use React Router with lazy-loaded page components (one per route); place page-scoped sub-components in pages/<page-name>/ subdirectories

Files:

  • web/src/pages/org/OrgChartSkeleton.stories.tsx
  • web/src/pages/org/status-mapping.ts
  • web/src/pages/org/DepartmentGroupNode.tsx
  • web/src/pages/org/OrgChartToolbar.stories.tsx
  • web/src/pages/org/DepartmentGroupNode.stories.tsx
  • web/src/pages/org/NodeContextMenu.tsx
  • web/src/pages/org/AgentNode.tsx
  • web/src/pages/org/DepartmentStatsBar.tsx
  • web/src/pages/org/CeoNode.tsx
  • web/src/pages/org/AgentNode.stories.tsx
  • web/src/pages/org/DepartmentStatsBar.stories.tsx
  • web/src/pages/org/OrgChartToolbar.tsx
  • web/src/pages/org/NodeContextMenu.stories.tsx
  • web/src/pages/org/build-org-tree.ts
  • web/src/pages/org/CeoNode.stories.tsx
  • web/src/pages/org/layout.ts
  • web/src/pages/OrgChartPage.tsx
web/**/*.stories.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

web/**/*.stories.{ts,tsx}: In Storybook, use parameters.backgrounds.options (object keyed by name) and initialGlobals.backgrounds.value for background configuration
In Storybook, use parameters.a11y.test: 'error' | 'todo' | 'off' for a11y testing configuration (replaces old .element and .manual)

Files:

  • web/src/pages/org/OrgChartSkeleton.stories.tsx
  • web/src/pages/org/OrgChartToolbar.stories.tsx
  • web/src/pages/org/DepartmentGroupNode.stories.tsx
  • web/src/pages/org/AgentNode.stories.tsx
  • web/src/pages/org/DepartmentStatsBar.stories.tsx
  • web/src/pages/org/NodeContextMenu.stories.tsx
  • web/src/pages/org/CeoNode.stories.tsx
web/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use ESLint with @eslint-react/eslint-plugin and eslint-plugin-security in web dashboard

Files:

  • web/src/pages/org/OrgChartSkeleton.stories.tsx
  • web/src/pages/org/status-mapping.ts
  • web/src/__tests__/pages/org/DepartmentStatsBar.test.tsx
  • web/src/__tests__/pages/org/OrgChartToolbar.test.tsx
  • web/src/pages/org/DepartmentGroupNode.tsx
  • web/src/__tests__/pages/org/layout.test.ts
  • web/src/pages/org/OrgChartToolbar.stories.tsx
  • web/src/__tests__/pages/org/NodeContextMenu.test.tsx
  • web/src/pages/org/DepartmentGroupNode.stories.tsx
  • web/src/pages/org/NodeContextMenu.tsx
  • web/src/pages/org/AgentNode.tsx
  • web/src/pages/org/DepartmentStatsBar.tsx
  • web/src/pages/org/CeoNode.tsx
  • web/src/pages/org/AgentNode.stories.tsx
  • web/src/stores/company.ts
  • web/src/pages/org/DepartmentStatsBar.stories.tsx
  • web/src/hooks/useOrgChartData.ts
  • web/src/__tests__/pages/org/build-org-tree.test.ts
  • web/src/pages/org/OrgChartToolbar.tsx
  • web/src/pages/org/NodeContextMenu.stories.tsx
  • web/src/pages/org/build-org-tree.ts
  • web/src/pages/org/CeoNode.stories.tsx
  • web/src/__tests__/stores/company.test.ts
  • web/src/pages/org/layout.ts
  • web/src/pages/OrgChartPage.tsx
web/**

📄 CodeRabbit inference engine (CLAUDE.md)

Use Node.js 22+ and npm for web dashboard; all dependencies in web/package.json (React 19, react-router, shadcn/ui, Radix UI, Tailwind CSS 4, Zustand, Recharts, Framer Motion, Axios, Lucide React, Geist fonts, Storybook 10, Vitest, ESLint, fast-check, etc.)

Files:

  • web/src/pages/org/OrgChartSkeleton.stories.tsx
  • web/src/pages/org/status-mapping.ts
  • web/src/__tests__/pages/org/DepartmentStatsBar.test.tsx
  • web/src/__tests__/pages/org/OrgChartToolbar.test.tsx
  • web/src/pages/org/DepartmentGroupNode.tsx
  • web/src/__tests__/pages/org/layout.test.ts
  • web/src/pages/org/OrgChartToolbar.stories.tsx
  • web/src/__tests__/pages/org/NodeContextMenu.test.tsx
  • web/src/pages/org/DepartmentGroupNode.stories.tsx
  • web/src/pages/org/NodeContextMenu.tsx
  • web/src/pages/org/AgentNode.tsx
  • web/src/pages/org/DepartmentStatsBar.tsx
  • web/src/pages/org/CeoNode.tsx
  • web/src/pages/org/AgentNode.stories.tsx
  • web/src/stores/company.ts
  • web/src/pages/org/DepartmentStatsBar.stories.tsx
  • web/src/hooks/useOrgChartData.ts
  • web/src/__tests__/pages/org/build-org-tree.test.ts
  • web/src/pages/org/OrgChartToolbar.tsx
  • web/src/pages/org/NodeContextMenu.stories.tsx
  • web/src/pages/org/build-org-tree.ts
  • web/src/pages/org/CeoNode.stories.tsx
  • web/src/__tests__/stores/company.test.ts
  • web/src/pages/org/layout.ts
  • web/src/pages/OrgChartPage.tsx
web/src/__tests__/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

web/src/__tests__/**/*.{ts,tsx}: Use fast-check for property-based testing in React; use fc.assert and fc.property
Use Vitest for React unit testing with coverage scoped to files changed vs origin/main

Files:

  • web/src/__tests__/pages/org/DepartmentStatsBar.test.tsx
  • web/src/__tests__/pages/org/OrgChartToolbar.test.tsx
  • web/src/__tests__/pages/org/layout.test.ts
  • web/src/__tests__/pages/org/NodeContextMenu.test.tsx
  • web/src/__tests__/pages/org/build-org-tree.test.ts
  • web/src/__tests__/stores/company.test.ts
web/src/stores/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use Zustand stores in web dashboard for state management (auth, WebSocket, toast, analytics, domain shells)

Files:

  • web/src/stores/company.ts
🧠 Learnings (34)
📓 Common learnings
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/).
📚 Learning: 2026-03-27T09:44:40.059Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T09:44:40.059Z
Learning: Applies to web/src/components/**/*.stories.{ts,tsx} : Use Storybook 10 (ESM-only) for React component documentation; import from `storybook/test`, `storybook/actions`; use `definePreview` from `storybook/react-vite`

Applied to files:

  • web/src/pages/org/OrgChartSkeleton.stories.tsx
  • web/src/__tests__/pages/org/OrgChartToolbar.test.tsx
  • web/src/pages/org/OrgChartToolbar.stories.tsx
  • web/src/pages/org/DepartmentGroupNode.stories.tsx
  • web/src/pages/org/AgentNode.stories.tsx
  • web/src/pages/org/DepartmentStatsBar.stories.tsx
  • web/src/pages/org/NodeContextMenu.stories.tsx
  • web/src/pages/org/CeoNode.stories.tsx
  • web/src/__tests__/stores/company.test.ts
📚 Learning: 2026-03-27T09:44:40.059Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T09:44:40.059Z
Learning: Applies to web/**/*.stories.{ts,tsx} : In Storybook, use `parameters.a11y.test: 'error' | 'todo' | 'off'` for a11y testing configuration (replaces old `.element` and `.manual`)

Applied to files:

  • web/src/pages/org/OrgChartSkeleton.stories.tsx
  • web/src/__tests__/pages/org/OrgChartToolbar.test.tsx
  • web/src/pages/org/OrgChartToolbar.stories.tsx
  • web/src/pages/org/DepartmentGroupNode.stories.tsx
  • web/src/pages/org/AgentNode.stories.tsx
  • web/src/pages/org/DepartmentStatsBar.stories.tsx
  • web/src/pages/org/NodeContextMenu.stories.tsx
  • web/src/pages/org/CeoNode.stories.tsx
📚 Learning: 2026-03-27T09:44:40.059Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T09:44:40.059Z
Learning: Applies to web/src/components/ui/**/*.{ts,tsx} : When creating new shared React components, place them in `web/src/components/ui/` with kebab-case filename, create accompanying `.stories.tsx` Storybook file with all states, export TypeScript interface for props, and use design tokens exclusively

Applied to files:

  • web/src/pages/org/OrgChartSkeleton.stories.tsx
  • CLAUDE.md
  • web/src/pages/org/OrgChartToolbar.stories.tsx
  • web/src/pages/org/DepartmentGroupNode.stories.tsx
  • web/src/pages/org/DepartmentStatsBar.tsx
  • web/src/pages/org/AgentNode.stories.tsx
  • web/src/pages/org/DepartmentStatsBar.stories.tsx
  • web/src/pages/org/OrgChartToolbar.tsx
  • web/src/pages/org/NodeContextMenu.stories.tsx
  • web/src/pages/org/CeoNode.stories.tsx
📚 Learning: 2026-03-27T09:44:40.059Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T09:44:40.059Z
Learning: Applies to web/**/*.stories.{ts,tsx} : In Storybook, use `parameters.backgrounds.options` (object keyed by name) and `initialGlobals.backgrounds.value` for background configuration

Applied to files:

  • web/src/pages/org/OrgChartSkeleton.stories.tsx
  • web/src/pages/org/OrgChartToolbar.stories.tsx
  • web/src/pages/org/DepartmentGroupNode.stories.tsx
  • web/src/pages/org/DepartmentStatsBar.stories.tsx
📚 Learning: 2026-03-27T09:44:40.059Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T09:44:40.059Z
Learning: Applies to web/.storybook/**/*.{ts,tsx} : In Storybook, use type-safe config with `defineMain` from `storybook/react-vite/node` and `definePreview` from `storybook/react-vite`; include explicit `framework` field

Applied to files:

  • web/src/pages/org/OrgChartSkeleton.stories.tsx
  • web/src/pages/org/OrgChartToolbar.stories.tsx
  • web/src/pages/org/DepartmentGroupNode.stories.tsx
  • web/src/pages/org/AgentNode.stories.tsx
  • web/src/pages/org/DepartmentStatsBar.stories.tsx
  • web/src/pages/org/NodeContextMenu.stories.tsx
  • web/src/pages/org/CeoNode.stories.tsx
📚 Learning: 2026-03-27T09:44:40.059Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T09:44:40.059Z
Learning: Applies to web/.storybook/preview.tsx : In Storybook, set a11y testing globally in `preview.tsx` with `parameters.a11y.test: 'error'` to enforce WCAG compliance on all stories

Applied to files:

  • web/src/pages/org/OrgChartSkeleton.stories.tsx
  • web/src/pages/org/OrgChartToolbar.stories.tsx
  • web/src/pages/org/DepartmentGroupNode.stories.tsx
  • web/src/pages/org/AgentNode.stories.tsx
  • web/src/pages/org/OrgChartToolbar.tsx
  • web/src/pages/org/NodeContextMenu.stories.tsx
  • web/src/pages/org/CeoNode.stories.tsx
📚 Learning: 2026-03-27T09:44:40.059Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T09:44:40.059Z
Learning: Applies to web/src/**/*.{ts,tsx} : Use shadow and border token variables in web components (`var(--so-shadow-card-hover)`, `border-border`, `border-bright`); never hardcode shadow or border styles

Applied to files:

  • web/src/pages/org/OrgChartSkeleton.stories.tsx
  • web/src/pages/org/AgentNode.tsx
  • web/src/pages/org/CeoNode.tsx
📚 Learning: 2026-03-27T09:44:40.059Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T09:44:40.059Z
Learning: Applies to web/src/**/*.{ts,tsx} : Use design tokens exclusively in web components: Tailwind semantic classes (`text-foreground`, `bg-card`, `text-accent`, `text-success`, `bg-danger`, etc.) or CSS variables (`var(--so-accent)`); never hardcode hex values or pixel spacing

Applied to files:

  • web/src/pages/org/OrgChartSkeleton.stories.tsx
  • web/src/pages/org/AgentNode.tsx
  • web/src/pages/org/CeoNode.tsx
📚 Learning: 2026-03-27T09:44:40.059Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T09:44:40.059Z
Learning: Applies to web/src/**/*.{ts,tsx} : Always reuse existing components from `web/src/components/ui/` (StatusBadge, MetricCard, Sparkline, SectionCard, AgentCard, DeptHealthBar, ProgressGauge, StatPill, Avatar, Button, Toast, Skeleton, EmptyState, ErrorBoundary, ConfirmDialog, CommandPalette, InlineEdit, AnimatedPresence, StaggerGroup/StaggerItem) before creating new ones

Applied to files:

  • web/src/pages/org/OrgChartSkeleton.stories.tsx
  • web/src/__tests__/pages/org/DepartmentStatsBar.test.tsx
  • web/src/pages/org/DepartmentGroupNode.tsx
  • web/src/pages/org/AgentNode.tsx
  • web/src/pages/org/DepartmentStatsBar.tsx
  • web/src/pages/org/CeoNode.tsx
  • web/src/pages/org/DepartmentStatsBar.stories.tsx
  • web/src/hooks/useOrgChartData.ts
  • web/src/pages/org/CeoNode.stories.tsx
  • web/src/pages/OrgChartPage.tsx
📚 Learning: 2026-03-27T09:44:40.059Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T09:44:40.059Z
Learning: Applies to web/src/**/*.{ts,tsx} : Do not recreate status dots inline; use `<StatusBadge>` component

Applied to files:

  • web/src/pages/org/OrgChartSkeleton.stories.tsx
  • web/src/pages/org/AgentNode.tsx
  • web/src/pages/org/DepartmentStatsBar.tsx
  • web/src/pages/org/CeoNode.stories.tsx
📚 Learning: 2026-03-27T09:44:40.059Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T09:44:40.059Z
Learning: Applies to web/src/**/*.{ts,tsx} : Use React 19 with TypeScript 6+ in web dashboard; enforce design tokens (no hardcoded colors, fonts, spacing) and reuse components from `web/src/components/ui/`

Applied to files:

  • web/src/pages/org/OrgChartSkeleton.stories.tsx
  • CLAUDE.md
  • web/src/pages/org/DepartmentGroupNode.tsx
  • web/src/pages/org/DepartmentGroupNode.stories.tsx
  • web/src/pages/org/NodeContextMenu.tsx
  • web/src/pages/org/AgentNode.tsx
  • web/src/pages/org/DepartmentStatsBar.tsx
  • web/src/pages/org/CeoNode.tsx
  • web/src/hooks/useOrgChartData.ts
  • web/src/pages/org/OrgChartToolbar.tsx
  • web/src/pages/org/layout.ts
  • web/src/pages/OrgChartPage.tsx
📚 Learning: 2026-03-19T07:13:44.964Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:13:44.964Z
Learning: Applies to src/synthorg/hr/**/*.py : HR package (hr/): hiring, firing, onboarding, offboarding, agent registry, performance tracking (task metrics, collaboration scoring, LLM calibration, collaboration overrides, trend detection), promotion/demotion (criteria evaluation, approval strategies, model mapping)

Applied to files:

  • web/src/pages/org/status-mapping.ts
📚 Learning: 2026-03-16T06:24:56.341Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-16T06:24:56.341Z
Learning: Applies to src/synthorg/hr/**/*.py : HR engine must provide: hiring, firing, onboarding, offboarding, agent registry, performance tracking (task metrics, collaboration scoring, trend detection), promotion/demotion

Applied to files:

  • web/src/pages/org/status-mapping.ts
📚 Learning: 2026-03-27T09:44:40.059Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T09:44:40.059Z
Learning: Applies to web/src/__tests__/**/*.{ts,tsx} : Use Vitest for React unit testing with coverage scoped to files changed vs origin/main

Applied to files:

  • web/src/__tests__/pages/org/DepartmentStatsBar.test.tsx
  • web/src/__tests__/pages/org/OrgChartToolbar.test.tsx
  • web/src/__tests__/pages/org/layout.test.ts
  • web/src/__tests__/pages/org/NodeContextMenu.test.tsx
  • web/src/__tests__/pages/org/build-org-tree.test.ts
  • web/src/__tests__/stores/company.test.ts
📚 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/src/__tests__/pages/org/DepartmentStatsBar.test.tsx
  • CLAUDE.md
  • web/src/__tests__/pages/org/OrgChartToolbar.test.tsx
  • web/src/__tests__/pages/org/layout.test.ts
  • web/src/__tests__/pages/org/NodeContextMenu.test.tsx
  • web/src/__tests__/pages/org/build-org-tree.test.ts
  • web/src/__tests__/stores/company.test.ts
📚 Learning: 2026-03-27T09:44:40.059Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T09:44:40.059Z
Learning: Applies to web/src/__tests__/**/*.{ts,tsx} : Use fast-check for property-based testing in React; use `fc.assert` and `fc.property`

Applied to files:

  • web/src/__tests__/pages/org/DepartmentStatsBar.test.tsx
  • web/src/__tests__/pages/org/OrgChartToolbar.test.tsx
  • web/src/__tests__/pages/org/NodeContextMenu.test.tsx
  • web/src/__tests__/pages/org/build-org-tree.test.ts
  • web/src/__tests__/stores/company.test.ts
📚 Learning: 2026-03-27T09:44:40.059Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T09:44:40.059Z
Learning: Applies to web/src/stores/**/*.{ts,tsx} : Use Zustand stores in web dashboard for state management (auth, WebSocket, toast, analytics, domain shells)

Applied to files:

  • CLAUDE.md
  • web/src/stores/company.ts
  • web/src/__tests__/stores/company.test.ts
📚 Learning: 2026-03-27T09:44:40.059Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T09:44:40.059Z
Learning: Applies to web/** : Use Node.js 22+ and npm for web dashboard; all dependencies in `web/package.json` (React 19, react-router, shadcn/ui, Radix UI, Tailwind CSS 4, Zustand, Recharts, Framer Motion, Axios, Lucide React, Geist fonts, Storybook 10, Vitest, ESLint, fast-check, etc.)

Applied to files:

  • CLAUDE.md
  • web/src/pages/org/DepartmentGroupNode.tsx
  • web/src/pages/org/CeoNode.tsx
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to src/synthorg/**/*.py : Package structure: src/synthorg/ organized as: api/ (REST+WebSocket, Litestar), auth/ (auth subpackage), backup/ (scheduled/manual backups), budget/ (cost tracking, CFO), cli/ (superseded by Go CLI), communication/ (message bus, meetings), config/ (YAML loading), core/ (domain models, resilience config), engine/ (orchestration, task state, coordination, approval gates, stagnation detection, context budget, compaction), hr/ (hiring, performance, promotion), memory/ (pluggable backend, Mem0, retrieval, consolidation), persistence/ (operational data, SQLite, settings), observability/ (logging, correlation, sinks), providers/ (LLM abstraction, LiteLLM, auth types, presets, runtime CRUD), settings/ (runtime-editable, typed definitions, encryption, config bridge), security/ (SecOps, rule engine, output scanning, progressive trust, autonomy levels), templates/ (company templates, personalities), tools/ (registry, built-in tools, git, sandbox, code_runner, MCP...

Applied to files:

  • CLAUDE.md
📚 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:

  • CLAUDE.md
  • web/src/pages/org/DepartmentStatsBar.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: 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:

  • CLAUDE.md
📚 Learning: 2026-03-27T09:44:40.059Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T09:44:40.059Z
Learning: Applies to web/src/pages/**/*.{ts,tsx} : Use React Router with lazy-loaded page components (one per route); place page-scoped sub-components in `pages/<page-name>/` subdirectories

Applied to files:

  • CLAUDE.md
  • web/src/pages/org/layout.ts
📚 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:

  • CLAUDE.md
  • web/src/pages/org/CeoNode.tsx
📚 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: Go 1.26+ required; CLI dependencies in `cli/go.mod` (Cobra, charmbracelet/huh, charmbracelet/lipgloss, sigstore-go, go-containerregistry, go-tuf)

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: Applies to pyproject.toml : Dependencies: all versions use == in pyproject.toml. Groups: test (pytest + plugins, hypothesis), dev (includes test + ruff, mypy, pre-commit, commitizen, pip-audit). Required: mem0ai (Mem0 memory backend — the default and currently only backend). Install: uv sync installs everything (dev group is default).

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: 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:

  • 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: Applies to go.mod : Maintain Go 1.26+ requirement. Dependencies: Cobra (CLI framework), charmbracelet/huh and charmbracelet/lipgloss (UI), sigstore-go (code signing), go-containerregistry (container image verification), go-tuf (TUF client for Sigstore).

Applied to files:

  • CLAUDE.md
📚 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: Applies to cli/go.mod : CLI uses Go 1.26+. Dependencies: Cobra, charmbracelet/huh, charmbracelet/lipgloss, sigstore-go, go-containerregistry, go-tuf

Applied to files:

  • CLAUDE.md
📚 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 cli/**/*.go : Go CLI (Go 1.26+) uses Cobra for commands, charmbracelet/huh for interactive CLI, charmbracelet/lipgloss for styled output. Cross-platform builds (linux/darwin/windows × amd64/arm64). GoReleaser for releases with cosign keyless signing of checksums.txt. SLSA L3 provenance attestations via actions/attest-build-provenance.

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: Applies to cli/** : CLI: Go 1.26+, dependencies in cli/go.mod (Cobra, charmbracelet/huh).

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-27T09:44:40.059Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T09:44:40.059Z
Learning: Applies to web/src/**/*.{ts,tsx} : Use density-aware spacing tokens in web components (`p-card`, `gap-section-gap`, `gap-grid-gap`) or standard Tailwind spacing; never hardcode pixel values for layout spacing

Applied to files:

  • web/src/pages/org/AgentNode.tsx
  • web/src/pages/org/CeoNode.tsx
📚 Learning: 2026-03-27T09:44:40.059Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T09:44:40.059Z
Learning: Applies to web/src/**/*.{ts,tsx} : In React components, import `cn` from `@/lib/utils` for conditional class merging; never concatenate class strings directly

Applied to files:

  • web/src/pages/org/CeoNode.tsx
📚 Learning: 2026-03-27T09:44:40.059Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T09:44:40.059Z
Learning: Applies to web/**/*.{ts,tsx} : Use ESLint with eslint-react/eslint-plugin and eslint-plugin-security in web dashboard

Applied to files:

  • web/src/hooks/useOrgChartData.ts
🔇 Additional comments (24)
CLAUDE.md (3)

127-127: Good clarification for hooks scope.

Including “page data composition” makes the web/src/hooks/ boundary clearer and matches the new Org Chart composition hook work.

Based on learnings: “Applies to web/src/**/*.{ts,tsx}: Use React 19 with TypeScript 6+ in web dashboard…”


131-131: Store taxonomy update is accurate and useful.

Explicitly listing company/agents/domain stores improves discoverability and matches the Zustand direction for the web dashboard.

Based on learnings: “Applies to web/src/stores/**/*.{ts,tsx}: Use Zustand stores in web dashboard for state management…”


321-321: Dependency list update looks consistent with the feature set.

Adding @dagrejs/dagre in the documented web stack aligns with the new auto-layout implementation and keeps CLAUDE.md in sync.

web/src/pages/org/OrgChartSkeleton.stories.tsx (1)

1-23: LGTM!

The story is well-structured with proper Storybook 10 typing, autodocs tag, and parameters.a11y.test: 'error' configuration. The previous feedback about inline background styling has been addressed—the decorator now only sets height for layout purposes.

web/src/pages/org/status-mapping.ts (1)

1-30: LGTM!

Clean utility implementation with exhaustive switch coverage for all AgentStatus values. The previous feedback about combining fall-through cases for 'onboarding' and 'active' has been addressed (lines 14-16). The resolveRuntimeStatus function correctly prioritizes WebSocket-pushed status over HR-derived defaults using nullish coalescing.

web/src/pages/org/NodeContextMenu.tsx (1)

1-139: LGTM!

All previous feedback has been addressed:

  • CEO nodes now have their own ceoItems array (lines 99-108) with only "View Details", preventing accidental inheritance of agent CRUD actions.
  • The selection logic (lines 110-111) correctly handles all three node types.
  • Buttons include type="button" (line 124) to prevent accidental form submission.

The component properly implements accessibility with role="menu" and role="menuitem", uses design tokens for styling, and cleans up event listeners on unmount.

web/src/pages/org/NodeContextMenu.stories.tsx (1)

1-48: LGTM!

All previous feedback has been addressed:

  • Accessibility testing is configured with parameters.a11y.test: 'error' (line 9).
  • The CeoMenu story (lines 41-48) has been added for complete coverage of all three nodeType variants.

The decorator correctly provides relative positioning context for the fixed-position menu component.

web/src/pages/org/AgentNode.tsx (1)

1-60: LGTM!

The previous feedback about hardcoded pixel widths has been addressed—the component now uses standard Tailwind spacing classes (min-w-36 max-w-44 on line 27).

The implementation properly:

  • Reuses Avatar and StatusBadge from @/components/ui/
  • Uses design tokens for all colors and borders
  • Provides accessibility via aria-label with agent context
  • Covers all getStatusColor outputs in STATUS_RING_CLASSES with a sensible fallback
web/src/pages/org/AgentNode.stories.tsx (1)

1-69: LGTM!

The previous feedback about missing a11y configuration has been addressed with parameters.a11y.test: 'error' (lines 38-40).

The stories provide complete coverage of all four AgentRuntimeStatus values (active, idle, error, offline) with a well-structured Wrapper component that properly initializes the React Flow context needed for node rendering.

web/src/__tests__/pages/org/DepartmentStatsBar.test.tsx (1)

1-32: LGTM!

The test suite provides good coverage of the DepartmentStatsBar component:

  • Parameterized tests verify all stat values and labels render correctly
  • Conditional cost rendering is tested for both provided and null cases
  • Component testability is verified via data-testid

The use of it.each with unique values (5, 3, 8) is a clean approach for testing the stats display.

web/src/__tests__/pages/org/OrgChartToolbar.test.tsx (1)

1-52: LGTM!

The previous feedback about shared mock instances has been addressed—the createProps() factory function (lines 6-12) creates fresh vi.fn() mocks for each test invocation, preventing state leakage between tests.

The test suite provides comprehensive coverage of the toolbar's render states and callback handlers with proper mock isolation.

web/src/pages/org/OrgChartToolbar.stories.tsx (1)

1-30: LGTM!

The story correctly uses interactive state management for viewMode, includes proper a11y testing configuration (parameters.a11y.test: 'error'), and follows Storybook conventions.

web/src/__tests__/pages/org/layout.test.ts (1)

1-104: LGTM!

Comprehensive test coverage for applyDagreLayout including edge cases (empty input, invalid edges, department grouping). The test descriptions accurately reflect the assertions.

web/src/pages/org/CeoNode.tsx (1)

1-52: LGTM!

Clean implementation reusing Avatar and StatusBadge components. Design tokens are used correctly throughout, and the Tailwind v4 postfix important syntax (bg-accent! size-1.5!) is properly applied. Good accessibility attributes with aria-label and data-testid.

web/src/pages/org/DepartmentStatsBar.tsx (1)

1-30: LGTM!

Clean implementation reusing StatPill component. The currency default correctly aligns with costUsd semantics, and the conditional cost rendering handles null values appropriately.

web/src/__tests__/pages/org/NodeContextMenu.test.tsx (1)

22-69: Test coverage looks comprehensive.

Good coverage of menu rendering by node type, action handler verification, keyboard accessibility (Escape), and ARIA roles.

web/src/pages/org/DepartmentGroupNode.tsx (1)

1-51: LGTM!

Well-structured component with proper null handling for health-based styling. The fallback logic for taskCount (line 42) correctly handles the nullable field, while activeCount doesn't need a fallback since it's a required number per the DepartmentGroupData interface. Good use of design tokens and accessibility attributes.

web/src/pages/org/DepartmentGroupNode.stories.tsx (1)

1-87: LGTM!

Good story coverage across health states (Healthy/Warning/Critical) with appropriate a11y configuration. The Critical story correctly tests the costUsd: null edge case.

web/src/pages/org/DepartmentStatsBar.stories.tsx (1)

1-48: LGTM!

Well-organized stories with good variant coverage (Default, NoCost, ZeroActive). The decorator properly uses Tailwind classes (max-w-md) for width constraint.

web/src/pages/org/build-org-tree.ts (5)

23-32: Health fields are correctly nullable — past issue addressed.

The healthPercent, taskCount, and costUsd fields are now typed as number | null, allowing the renderer to distinguish between "0" and "unknown/loading" states. This addresses the previous review feedback about falsely displaying 100% health when the API is unavailable.


36-49: LGTM!

The seniority ranking is comprehensive and correctly ordered. The defensive fallback to -1 handles any hypothetical type widening gracefully.


96-118: Empty departments are now rendered — past issue addressed.

The previous review flagged that skipping deptMembers.length === 0 would hide newly created departments. This has been corrected: the loop now processes every configured department regardless of member count, and health fields default to null rather than falsely-healthy values.


183-196: LGTM!

Edge deduplication for CEO→department-head connections is correctly implemented, preventing duplicate edges when the CEO happens to also be connected via the team membership path.


68-78: Clean defensive handling for empty agent list.

Early-returning an empty graph when all agents are terminated prevents downstream layout errors and is a sensible guard.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 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/__tests__/pages/org/NodeContextMenu.test.tsx`:
- Around line 52-57: Add a test alongside the Escape key test in
NodeContextMenu.test.tsx that asserts the menu also closes on an outside click:
render <NodeContextMenu {...baseProps} onClose={onClose} />, then simulate a
document-level outside click (e.g., fireEvent.mouseDown(document, { button: 0 })
or fireEvent.mouseDown(document.body)) and expect the onClose mock to have been
called once; reference the NodeContextMenu component and the onClose mock used
in the existing test to implement this new assertion.
- Around line 22-69: Add a property-based test using fast-check in
NodeContextMenu.test.tsx that asserts an invariant across supported node types
(e.g., 'agent' and 'department'); import fc and use fc.assert(fc.property(...))
to generate nodeType values and render the NodeContextMenu component (using the
existing baseProps and the nodeType prop) and assert invariant DOM properties
such as presence of role="menu" and correct menuitem counts or presence/absence
of specific action labels; update tests referencing NodeContextMenu, baseProps,
and the nodeType prop to run inside the fc.property so the suite covers
randomized inputs per guidelines.

In `@web/src/hooks/useOrgChartData.ts`:
- Around line 31-35: The current useEffect calls fetchDepartmentHealths()
unconditionally in the .then() of fetchCompanyData(), which will run even if
fetchCompanyData recorded an error; change the flow in the useEffect that uses
useCompanyStore.getState() so you await fetchCompanyData() (or inspect its
returned value) and only call companyStore.fetchDepartmentHealths() when the
company load actually succeeded — for example check the store error/success flag
after fetchCompanyData() (or use its boolean result) before invoking
fetchDepartmentHealths(); update the useEffect to use async/await or conditional
.then() logic around fetchCompanyData, referencing useEffect,
useCompanyStore.getState(), fetchCompanyData, and fetchDepartmentHealths.

In `@web/src/pages/org/build-org-tree.ts`:
- Around line 76-78: The early return on agents.length in build-org-tree.ts
prevents department nodes from being emitted when there are no agents; remove or
relax the guard in the code that returns { nodes: [], edges: [] } so
department/group nodes are still created (look for the agents.length === 0 check
in the buildOrgTree logic), and then update applyDagreLayout (the function
responsible for layout/placement) to add a department-only layout branch that
positions empty department/group nodes and prevents them from collapsing
together (ensure it handles cases with nodes but no agent child nodes by
assigning distinct group bounding boxes or fixed positions).

In `@web/src/pages/org/layout.ts`:
- Around line 74-81: The empty-group grid currently seeds at origin causing
overlap; update the empty-group placement inside positionedGroups map (where
emptyGroupIndex is used) to compute start offsets from the maximal laid-out
bounds instead of (0,0): scan positionedLeafMap (and any already-positioned
groups) to compute maxX and maxY (e.g., max position.x + width and position.y +
height) and use those as xOffset/yOffset when computing each empty group's
position (col * 240 + xOffset, row * 140 + yOffset); keep the existing
width/height/style values and increment emptyGroupIndex as before.
🪄 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: 823cc153-930f-4eb2-96c8-03827857c6e2

📥 Commits

Reviewing files that changed from the base of the PR and between 6f095a1 and b73135e.

📒 Files selected for processing (5)
  • web/src/__tests__/pages/org/NodeContextMenu.test.tsx
  • web/src/hooks/useOrgChartData.ts
  • web/src/pages/OrgChartPage.tsx
  • web/src/pages/org/build-org-tree.ts
  • web/src/pages/org/layout.ts
📜 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 Web
  • GitHub Check: Build Backend
  • GitHub Check: Dependency Review
  • GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Use TypeScript 6+ with paths for module resolution (remove deprecated baseUrl); esModuleInterop is always true
In TypeScript, strict defaults to true and types defaults to []; do not auto-discover @types/* — must explicitly list needed types

Files:

  • web/src/pages/OrgChartPage.tsx
  • web/src/hooks/useOrgChartData.ts
  • web/src/pages/org/layout.ts
  • web/src/__tests__/pages/org/NodeContextMenu.test.tsx
  • web/src/pages/org/build-org-tree.ts
web/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

web/src/**/*.{ts,tsx}: Use React 19 with TypeScript 6+ in web dashboard; enforce design tokens (no hardcoded colors, fonts, spacing) and reuse components from web/src/components/ui/
Always reuse existing components from web/src/components/ui/ (StatusBadge, MetricCard, Sparkline, SectionCard, AgentCard, DeptHealthBar, ProgressGauge, StatPill, Avatar, Button, Toast, Skeleton, EmptyState, ErrorBoundary, ConfirmDialog, CommandPalette, InlineEdit, AnimatedPresence, StaggerGroup/StaggerItem) before creating new ones
Use design tokens exclusively in web components: Tailwind semantic classes (text-foreground, bg-card, text-accent, text-success, bg-danger, etc.) or CSS variables (var(--so-accent)); never hardcode hex values or pixel spacing
Use font-sans or font-mono (Geist tokens) in web components; never set fontFamily directly
Use density-aware spacing tokens in web components (p-card, gap-section-gap, gap-grid-gap) or standard Tailwind spacing; never hardcode pixel values for layout spacing
Use shadow and border token variables in web components (var(--so-shadow-card-hover), border-border, border-bright); never hardcode shadow or border styles
In React components, import cn from @/lib/utils for conditional class merging; never concatenate class strings directly
Do not recreate status dots inline; use <StatusBadge> component
Do not build card-with-header layouts from scratch; use <SectionCard> component
Do not create metric displays with text-metric font-bold; use <MetricCard> component
Do not render initials circles manually; use <Avatar> component
Do not create complex (>8 line) JSX inside .map() blocks; extract to a shared component

Files:

  • web/src/pages/OrgChartPage.tsx
  • web/src/hooks/useOrgChartData.ts
  • web/src/pages/org/layout.ts
  • web/src/__tests__/pages/org/NodeContextMenu.test.tsx
  • web/src/pages/org/build-org-tree.ts
web/src/pages/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use React Router with lazy-loaded page components (one per route); place page-scoped sub-components in pages/<page-name>/ subdirectories

Files:

  • web/src/pages/OrgChartPage.tsx
  • web/src/pages/org/layout.ts
  • web/src/pages/org/build-org-tree.ts
web/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use ESLint with @eslint-react/eslint-plugin and eslint-plugin-security in web dashboard

Files:

  • web/src/pages/OrgChartPage.tsx
  • web/src/hooks/useOrgChartData.ts
  • web/src/pages/org/layout.ts
  • web/src/__tests__/pages/org/NodeContextMenu.test.tsx
  • web/src/pages/org/build-org-tree.ts
web/**

📄 CodeRabbit inference engine (CLAUDE.md)

Use Node.js 22+ and npm for web dashboard; all dependencies in web/package.json (React 19, react-router, shadcn/ui, Radix UI, Tailwind CSS 4, Zustand, Recharts, Framer Motion, Axios, Lucide React, Geist fonts, Storybook 10, Vitest, ESLint, fast-check, etc.)

Files:

  • web/src/pages/OrgChartPage.tsx
  • web/src/hooks/useOrgChartData.ts
  • web/src/pages/org/layout.ts
  • web/src/__tests__/pages/org/NodeContextMenu.test.tsx
  • web/src/pages/org/build-org-tree.ts
web/src/__tests__/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

web/src/__tests__/**/*.{ts,tsx}: Use fast-check for property-based testing in React; use fc.assert and fc.property
Use Vitest for React unit testing with coverage scoped to files changed vs origin/main

Files:

  • web/src/__tests__/pages/org/NodeContextMenu.test.tsx
🧠 Learnings (11)
📓 Common learnings
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/).
📚 Learning: 2026-03-27T09:44:40.059Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T09:44:40.059Z
Learning: Applies to web/src/**/*.{ts,tsx} : Use React 19 with TypeScript 6+ in web dashboard; enforce design tokens (no hardcoded colors, fonts, spacing) and reuse components from `web/src/components/ui/`

Applied to files:

  • web/src/pages/OrgChartPage.tsx
  • web/src/hooks/useOrgChartData.ts
  • web/src/pages/org/layout.ts
📚 Learning: 2026-03-27T09:44:40.059Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T09:44:40.059Z
Learning: Applies to web/src/**/*.{ts,tsx} : Always reuse existing components from `web/src/components/ui/` (StatusBadge, MetricCard, Sparkline, SectionCard, AgentCard, DeptHealthBar, ProgressGauge, StatPill, Avatar, Button, Toast, Skeleton, EmptyState, ErrorBoundary, ConfirmDialog, CommandPalette, InlineEdit, AnimatedPresence, StaggerGroup/StaggerItem) before creating new ones

Applied to files:

  • web/src/pages/OrgChartPage.tsx
  • web/src/hooks/useOrgChartData.ts
📚 Learning: 2026-03-27T09:44:40.059Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T09:44:40.059Z
Learning: Applies to web/src/**/*.{ts,tsx} : Do not create complex (>8 line) JSX inside `.map()` blocks; extract to a shared component

Applied to files:

  • web/src/pages/OrgChartPage.tsx
📚 Learning: 2026-03-27T09:44:40.059Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T09:44:40.059Z
Learning: Applies to web/src/**/*.{ts,tsx} : Do not recreate status dots inline; use `<StatusBadge>` component

Applied to files:

  • web/src/pages/OrgChartPage.tsx
📚 Learning: 2026-03-27T09:44:40.059Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T09:44:40.059Z
Learning: Applies to web/**/*.{ts,tsx} : Use ESLint with eslint-react/eslint-plugin and eslint-plugin-security in web dashboard

Applied to files:

  • web/src/hooks/useOrgChartData.ts
📚 Learning: 2026-03-27T09:44:40.059Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T09:44:40.059Z
Learning: Applies to web/src/pages/**/*.{ts,tsx} : Use React Router with lazy-loaded page components (one per route); place page-scoped sub-components in `pages/<page-name>/` subdirectories

Applied to files:

  • web/src/pages/org/layout.ts
📚 Learning: 2026-03-27T09:44:40.059Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T09:44:40.059Z
Learning: Applies to web/src/__tests__/**/*.{ts,tsx} : Use Vitest for React unit testing with coverage scoped to files changed vs origin/main

Applied to files:

  • web/src/__tests__/pages/org/NodeContextMenu.test.tsx
📚 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/src/__tests__/pages/org/NodeContextMenu.test.tsx
📚 Learning: 2026-03-27T09:44:40.059Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T09:44:40.059Z
Learning: Applies to web/src/__tests__/**/*.{ts,tsx} : Use fast-check for property-based testing in React; use `fc.assert` and `fc.property`

Applied to files:

  • web/src/__tests__/pages/org/NodeContextMenu.test.tsx
📚 Learning: 2026-03-27T09:44:40.059Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T09:44:40.059Z
Learning: Applies to web/src/components/**/*.stories.{ts,tsx} : Use Storybook 10 (ESM-only) for React component documentation; import from `storybook/test`, `storybook/actions`; use `definePreview` from `storybook/react-vite`

Applied to files:

  • web/src/__tests__/pages/org/NodeContextMenu.test.tsx
🔇 Additional comments (3)
web/src/__tests__/pages/org/NodeContextMenu.test.tsx (1)

38-50: Callback argument assertions are correctly scoped to nodeId.

Line 42 and Line 49 match the component contract (onViewDetails(nodeId) / onDelete(nodeId)) and protect against accidental signature drift.

web/src/hooks/useOrgChartData.ts (1)

44-48: The eslint-disable still targets a nonexistent rule.

@eslint-react/eslint-plugin does not expose @eslint-react/exhaustive-deps, so this suppression is inert. Either switch it to react-hooks/exhaustive-deps after wiring eslint-plugin-react-hooks, or drop the disable entirely.

#!/bin/bash
configs="$(fd -t f 'eslint\.config\..*|\.eslintrc.*' .)"
printf '%s\n' "$configs"
rg -n "@eslint-react/exhaustive-deps|react-hooks/exhaustive-deps|eslint-plugin-react-hooks" web/src/hooks/useOrgChartData.ts web/package.json $configs
web/src/pages/OrgChartPage.tsx (1)

298-300: Good use of Button asChild here.

This keeps the CTA as a single interactive element and avoids the nested button/link accessibility issue.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (1)
web/src/hooks/useOrgChartData.ts (1)

31-38: ⚠️ Potential issue | 🟡 Minor

Health fetch still runs after failed company load.

The .then() callback executes regardless of whether fetchCompanyData() succeeded or recorded an error. While the config check on line 34 prevents calling fetchDepartmentHealths() when config is null, it doesn't distinguish between "not yet loaded" and "load failed with error". This can cause unnecessary API calls when the company endpoint is failing.

🛡️ Proposed fix to gate on success
   useEffect(() => {
-    const companyStore = useCompanyStore.getState()
-    companyStore.fetchCompanyData().then(() => {
-      if (useCompanyStore.getState().config) {
-        companyStore.fetchDepartmentHealths()
-      }
-    })
+    const load = async () => {
+      const companyStore = useCompanyStore.getState()
+      await companyStore.fetchCompanyData()
+      const { config, error } = useCompanyStore.getState()
+      if (!error && config) {
+        await companyStore.fetchDepartmentHealths()
+      }
+    }
+    void load()
   }, [])
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/hooks/useOrgChartData.ts` around lines 31 - 38, The current useEffect
calls useCompanyStore.getState().fetchCompanyData().then(...) which runs the
.then callback even when fetchCompanyData failed; change the effect to an async
flow and only call fetchDepartmentHealths when the company load succeeded:
inside useEffect create an async function that awaits
useCompanyStore.getState().fetchCompanyData(), then check a success indicator
(e.g. the resolved value or store flags like useCompanyStore.getState().config
and absence of useCompanyStore.getState().error) before calling
useCompanyStore.getState().fetchDepartmentHealths(); alternatively handle
rejection with try/catch and only call fetchDepartmentHealths in the try block
after successful await of fetchCompanyData().
🤖 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/pages/org/build-org-tree.ts`:
- Around line 207-220: The CEO selection currently uses a deterministic
"first-in-array wins" tiebreaker but this is implicit; add a clear comment in
findCeo and in findHighestSeniority stating that when multiple agents tie on
level/seniority the function returns the first matching element in array order
(due to using array filter + first element and the '>' comparison in the max
reduction), so maintainers know the intended deterministic behavior and can
change it intentionally if needed; place the comment immediately above the
findCeo and findHighestSeniority function definitions for visibility.

In `@web/src/pages/org/layout.ts`:
- Around line 35-37: The early return that maps all nodes to position {x:0,y:0}
when leafNodes.length === 0 causes overlapping; instead call or reuse the
empty-group positioning logic used later (the code that handles empty department
groups) so each department node gets a computed position rather than all at
(0,0). Replace the nodes.map fallback with a call into that empty-group
positioning routine (or inline the same placement calculation) so nodes are
spaced correctly when there are no leafNodes; update any references to
leafNodes/nodes accordingly.

---

Duplicate comments:
In `@web/src/hooks/useOrgChartData.ts`:
- Around line 31-38: The current useEffect calls
useCompanyStore.getState().fetchCompanyData().then(...) which runs the .then
callback even when fetchCompanyData failed; change the effect to an async flow
and only call fetchDepartmentHealths when the company load succeeded: inside
useEffect create an async function that awaits
useCompanyStore.getState().fetchCompanyData(), then check a success indicator
(e.g. the resolved value or store flags like useCompanyStore.getState().config
and absence of useCompanyStore.getState().error) before calling
useCompanyStore.getState().fetchDepartmentHealths(); alternatively handle
rejection with try/catch and only call fetchDepartmentHealths in the try block
after successful await of fetchCompanyData().
🪄 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: ad473a43-79c3-4b14-b3c0-bf442d75cdcf

📥 Commits

Reviewing files that changed from the base of the PR and between b73135e and 787d50c.

📒 Files selected for processing (4)
  • web/src/__tests__/pages/org/NodeContextMenu.test.tsx
  • web/src/hooks/useOrgChartData.ts
  • web/src/pages/org/build-org-tree.ts
  • web/src/pages/org/layout.ts
📜 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: Dashboard Test
  • GitHub Check: Build Backend
  • GitHub Check: Build Sandbox
  • GitHub Check: Dependency Review
  • GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Use TypeScript 6+ with paths for module resolution (remove deprecated baseUrl); esModuleInterop is always true
In TypeScript, strict defaults to true and types defaults to []; do not auto-discover @types/* — must explicitly list needed types

Files:

  • web/src/__tests__/pages/org/NodeContextMenu.test.tsx
  • web/src/pages/org/layout.ts
  • web/src/pages/org/build-org-tree.ts
  • web/src/hooks/useOrgChartData.ts
web/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

web/src/**/*.{ts,tsx}: Use React 19 with TypeScript 6+ in web dashboard; enforce design tokens (no hardcoded colors, fonts, spacing) and reuse components from web/src/components/ui/
Always reuse existing components from web/src/components/ui/ (StatusBadge, MetricCard, Sparkline, SectionCard, AgentCard, DeptHealthBar, ProgressGauge, StatPill, Avatar, Button, Toast, Skeleton, EmptyState, ErrorBoundary, ConfirmDialog, CommandPalette, InlineEdit, AnimatedPresence, StaggerGroup/StaggerItem) before creating new ones
Use design tokens exclusively in web components: Tailwind semantic classes (text-foreground, bg-card, text-accent, text-success, bg-danger, etc.) or CSS variables (var(--so-accent)); never hardcode hex values or pixel spacing
Use font-sans or font-mono (Geist tokens) in web components; never set fontFamily directly
Use density-aware spacing tokens in web components (p-card, gap-section-gap, gap-grid-gap) or standard Tailwind spacing; never hardcode pixel values for layout spacing
Use shadow and border token variables in web components (var(--so-shadow-card-hover), border-border, border-bright); never hardcode shadow or border styles
In React components, import cn from @/lib/utils for conditional class merging; never concatenate class strings directly
Do not recreate status dots inline; use <StatusBadge> component
Do not build card-with-header layouts from scratch; use <SectionCard> component
Do not create metric displays with text-metric font-bold; use <MetricCard> component
Do not render initials circles manually; use <Avatar> component
Do not create complex (>8 line) JSX inside .map() blocks; extract to a shared component

Files:

  • web/src/__tests__/pages/org/NodeContextMenu.test.tsx
  • web/src/pages/org/layout.ts
  • web/src/pages/org/build-org-tree.ts
  • web/src/hooks/useOrgChartData.ts
web/src/__tests__/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

web/src/__tests__/**/*.{ts,tsx}: Use fast-check for property-based testing in React; use fc.assert and fc.property
Use Vitest for React unit testing with coverage scoped to files changed vs origin/main

Files:

  • web/src/__tests__/pages/org/NodeContextMenu.test.tsx
web/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use ESLint with @eslint-react/eslint-plugin and eslint-plugin-security in web dashboard

Files:

  • web/src/__tests__/pages/org/NodeContextMenu.test.tsx
  • web/src/pages/org/layout.ts
  • web/src/pages/org/build-org-tree.ts
  • web/src/hooks/useOrgChartData.ts
web/**

📄 CodeRabbit inference engine (CLAUDE.md)

Use Node.js 22+ and npm for web dashboard; all dependencies in web/package.json (React 19, react-router, shadcn/ui, Radix UI, Tailwind CSS 4, Zustand, Recharts, Framer Motion, Axios, Lucide React, Geist fonts, Storybook 10, Vitest, ESLint, fast-check, etc.)

Files:

  • web/src/__tests__/pages/org/NodeContextMenu.test.tsx
  • web/src/pages/org/layout.ts
  • web/src/pages/org/build-org-tree.ts
  • web/src/hooks/useOrgChartData.ts
web/src/pages/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use React Router with lazy-loaded page components (one per route); place page-scoped sub-components in pages/<page-name>/ subdirectories

Files:

  • web/src/pages/org/layout.ts
  • web/src/pages/org/build-org-tree.ts
🧠 Learnings (11)
📓 Common learnings
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/).
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T09:44:40.059Z
Learning: Applies to web/** : Use Node.js 22+ and npm for web dashboard; all dependencies in `web/package.json` (React 19, react-router, shadcn/ui, Radix UI, Tailwind CSS 4, Zustand, Recharts, Framer Motion, Axios, Lucide React, Geist fonts, Storybook 10, Vitest, ESLint, fast-check, etc.)
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-27T09:44:40.059Z
Learning: Applies to web/src/**/*.{ts,tsx} : Always reuse existing components from `web/src/components/ui/` (StatusBadge, MetricCard, Sparkline, SectionCard, AgentCard, DeptHealthBar, ProgressGauge, StatPill, Avatar, Button, Toast, Skeleton, EmptyState, ErrorBoundary, ConfirmDialog, CommandPalette, InlineEdit, AnimatedPresence, StaggerGroup/StaggerItem) before creating new ones
📚 Learning: 2026-03-27T09:44:40.059Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T09:44:40.059Z
Learning: Applies to web/src/__tests__/**/*.{ts,tsx} : Use Vitest for React unit testing with coverage scoped to files changed vs origin/main

Applied to files:

  • web/src/__tests__/pages/org/NodeContextMenu.test.tsx
📚 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/src/__tests__/pages/org/NodeContextMenu.test.tsx
📚 Learning: 2026-03-27T09:44:40.059Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T09:44:40.059Z
Learning: Applies to web/src/__tests__/**/*.{ts,tsx} : Use fast-check for property-based testing in React; use `fc.assert` and `fc.property`

Applied to files:

  • web/src/__tests__/pages/org/NodeContextMenu.test.tsx
📚 Learning: 2026-03-27T09:44:40.059Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T09:44:40.059Z
Learning: Applies to web/src/**/*.{ts,tsx} : Use React 19 with TypeScript 6+ in web dashboard; enforce design tokens (no hardcoded colors, fonts, spacing) and reuse components from `web/src/components/ui/`

Applied to files:

  • web/src/__tests__/pages/org/NodeContextMenu.test.tsx
  • web/src/pages/org/layout.ts
  • web/src/pages/org/build-org-tree.ts
  • web/src/hooks/useOrgChartData.ts
📚 Learning: 2026-03-27T09:44:40.059Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T09:44:40.059Z
Learning: Applies to web/src/components/**/*.stories.{ts,tsx} : Use Storybook 10 (ESM-only) for React component documentation; import from `storybook/test`, `storybook/actions`; use `definePreview` from `storybook/react-vite`

Applied to files:

  • web/src/__tests__/pages/org/NodeContextMenu.test.tsx
📚 Learning: 2026-03-27T09:44:40.059Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T09:44:40.059Z
Learning: Applies to web/**/*.stories.{ts,tsx} : In Storybook, use `parameters.a11y.test: 'error' | 'todo' | 'off'` for a11y testing configuration (replaces old `.element` and `.manual`)

Applied to files:

  • web/src/__tests__/pages/org/NodeContextMenu.test.tsx
📚 Learning: 2026-03-27T09:44:40.059Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T09:44:40.059Z
Learning: Applies to web/src/pages/**/*.{ts,tsx} : Use React Router with lazy-loaded page components (one per route); place page-scoped sub-components in `pages/<page-name>/` subdirectories

Applied to files:

  • web/src/pages/org/layout.ts
📚 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/org/build-org-tree.ts
📚 Learning: 2026-03-27T09:44:40.059Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T09:44:40.059Z
Learning: Applies to web/src/**/*.{ts,tsx} : Always reuse existing components from `web/src/components/ui/` (StatusBadge, MetricCard, Sparkline, SectionCard, AgentCard, DeptHealthBar, ProgressGauge, StatPill, Avatar, Button, Toast, Skeleton, EmptyState, ErrorBoundary, ConfirmDialog, CommandPalette, InlineEdit, AnimatedPresence, StaggerGroup/StaggerItem) before creating new ones

Applied to files:

  • web/src/hooks/useOrgChartData.ts
📚 Learning: 2026-03-27T09:44:40.059Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T09:44:40.059Z
Learning: Applies to web/**/*.{ts,tsx} : Use ESLint with eslint-react/eslint-plugin and eslint-plugin-security in web dashboard

Applied to files:

  • web/src/hooks/useOrgChartData.ts
🔇 Additional comments (17)
web/src/__tests__/pages/org/NodeContextMenu.test.tsx (3)

1-21: LGTM!

The test setup correctly addresses previous review feedback: imports are complete (including beforeEach), and the beforeEach block properly resets baseProps with a fresh mock for test isolation. Tests that need to assert on callbacks create local mocks, which is the right pattern.


23-86: Good test coverage for core functionality.

The tests correctly verify:

  • Menu items for different node types (agent: 4 items, department: 3 items)
  • Callback wiring (onViewDetails, onDelete) with correct nodeId argument
  • Close behaviors (Escape key, outside click)
  • Accessibility roles (menu, menuitem)

One minor gap: there's no explicit test for the ceo node type menu items (which per the component only shows "View Details"). The it.each covers that it renders something, but not the specific expected content.


88-106: Property-based test complies with guidelines and tests meaningful invariants.

The test correctly uses fc.assert and fc.property as required by coding guidelines. The invariants tested (menu role presence, at least one menu item, all items are buttons) are meaningful structural guarantees. The unmount() call properly cleans up the DOM between iterations.

web/src/hooks/useOrgChartData.ts (3)

46-50: Invalid ESLint rule reference remains unfixed.

The disable comment references @eslint-react/exhaustive-deps, but this rule doesn't exist in @eslint-react/eslint-plugin. The exhaustive-deps rule comes from eslint-plugin-react-hooks. Since eslint-plugin-react-hooks is not installed in this project, this comment has no effect.

Either install eslint-plugin-react-hooks and use react-hooks/exhaustive-deps, or remove the ineffective comment.


52-63: LGTM!

The WebSocket handler correctly dispatches events to both stores. As shown in the store implementations, each store filters for its own event types (agent.hired/agent.fired for company, agent.status_changed for agents), making this dual-dispatch pattern safe and appropriate.


69-75: LGTM!

The memoization correctly derives React Flow nodes/edges from store data with appropriate dependencies. The layout computation using fixed fallback dimensions (handled in applyDagreLayout) provides a stable initial layout before React Flow can measure actual node dimensions.

web/src/pages/org/layout.ts (5)

1-16: LGTM!

Clean imports and well-documented constants for layout configuration. The type definitions are appropriately scoped.


51-55: LGTM!

Good defensive check ensuring edges are only added when both source and target nodes exist in the graph. This handles edge cases like edges referencing missing nodes.


59-80: LGTM!

Correct coordinate transformation from dagre's center-based positioning to React Flow's top-left origin. The content bounds computation properly accounts for node dimensions to enable proper empty-group offsetting.


85-93: LGTM!

Empty department groups are now correctly offset beyond the content bounds (xOffset = contentMaxX + padding), preventing overlap with populated content. The 3-column grid layout provides clean organization for multiple empty departments.


115-124: LGTM!

Children positions are correctly converted to group-relative coordinates via immutable map updates. This ensures React Flow properly renders children within their parent group nodes.

web/src/pages/org/build-org-tree.ts (6)

1-56: LGTM!

Well-structured type definitions and seniority ranking. The index signature [key: string]: unknown on node data interfaces enables React Flow's type requirements while maintaining type safety for known properties.


73-89: LGTM!

Correct filtering of terminated agents and grouping by department. The CEO selection properly falls through the priority chain (executive c_suite → any c_suite → highest seniority).


99-114: LGTM!

Department group nodes correctly handle missing health data with nullable fields (?? null), allowing the UI to render appropriate loading/unknown states rather than falsely showing 100% health.


119-129: LGTM!

Team membership assignment correctly prevents overwrites with the !teamMemberSet.has(member.id) guard, ensuring consistent parent assignment when an agent appears in multiple teams (first team wins).


145-176: LGTM!

Node creation correctly assigns parentId for React Flow group containment. Edge creation properly establishes the reporting hierarchy: team members → team lead → department head → CEO, with appropriate deduplication.


222-229: LGTM!

findDepartmentHead correctly excludes the CEO when determining department leadership and properly passes the readonly array directly to findHighestSeniority.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 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/pages/org/layout.ts`:
- Around line 77-98: The empty-group branch in the positionedGroups map replaces
group.style entirely (returning { ...group, position: ..., style: { width: 200,
height: 100 } }) which loses existing style props; change it to merge the
existing style instead (e.g., style: { ...group.style, width: 200, height: 100
}) so it matches the other branches (see positionedGroups, groupNodes,
group.style, DEFAULT_GROUP_PADDING, emptyGroupIndex) and preserves pre-existing
style attributes.
🪄 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: 077bd051-227e-49aa-9261-a67fa5529d8e

📥 Commits

Reviewing files that changed from the base of the PR and between 787d50c and ad73997.

📒 Files selected for processing (2)
  • web/src/pages/org/build-org-tree.ts
  • web/src/pages/org/layout.ts
📜 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: Build Sandbox
  • GitHub Check: Dependency Review
  • GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Use TypeScript 6+ with paths for module resolution (remove deprecated baseUrl); esModuleInterop is always true
In TypeScript, strict defaults to true and types defaults to []; do not auto-discover @types/* — must explicitly list needed types

Files:

  • web/src/pages/org/layout.ts
  • web/src/pages/org/build-org-tree.ts
web/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

web/src/**/*.{ts,tsx}: Use React 19 with TypeScript 6+ in web dashboard; enforce design tokens (no hardcoded colors, fonts, spacing) and reuse components from web/src/components/ui/
Always reuse existing components from web/src/components/ui/ (StatusBadge, MetricCard, Sparkline, SectionCard, AgentCard, DeptHealthBar, ProgressGauge, StatPill, Avatar, Button, Toast, Skeleton, EmptyState, ErrorBoundary, ConfirmDialog, CommandPalette, InlineEdit, AnimatedPresence, StaggerGroup/StaggerItem) before creating new ones
Use design tokens exclusively in web components: Tailwind semantic classes (text-foreground, bg-card, text-accent, text-success, bg-danger, etc.) or CSS variables (var(--so-accent)); never hardcode hex values or pixel spacing
Use font-sans or font-mono (Geist tokens) in web components; never set fontFamily directly
Use density-aware spacing tokens in web components (p-card, gap-section-gap, gap-grid-gap) or standard Tailwind spacing; never hardcode pixel values for layout spacing
Use shadow and border token variables in web components (var(--so-shadow-card-hover), border-border, border-bright); never hardcode shadow or border styles
In React components, import cn from @/lib/utils for conditional class merging; never concatenate class strings directly
Do not recreate status dots inline; use <StatusBadge> component
Do not build card-with-header layouts from scratch; use <SectionCard> component
Do not create metric displays with text-metric font-bold; use <MetricCard> component
Do not render initials circles manually; use <Avatar> component
Do not create complex (>8 line) JSX inside .map() blocks; extract to a shared component

Files:

  • web/src/pages/org/layout.ts
  • web/src/pages/org/build-org-tree.ts
web/src/pages/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use React Router with lazy-loaded page components (one per route); place page-scoped sub-components in pages/<page-name>/ subdirectories

Files:

  • web/src/pages/org/layout.ts
  • web/src/pages/org/build-org-tree.ts
web/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use ESLint with @eslint-react/eslint-plugin and eslint-plugin-security in web dashboard

Files:

  • web/src/pages/org/layout.ts
  • web/src/pages/org/build-org-tree.ts
web/**

📄 CodeRabbit inference engine (CLAUDE.md)

Use Node.js 22+ and npm for web dashboard; all dependencies in web/package.json (React 19, react-router, shadcn/ui, Radix UI, Tailwind CSS 4, Zustand, Recharts, Framer Motion, Axios, Lucide React, Geist fonts, Storybook 10, Vitest, ESLint, fast-check, etc.)

Files:

  • web/src/pages/org/layout.ts
  • web/src/pages/org/build-org-tree.ts
🧠 Learnings (2)
📓 Common learnings
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/).
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T09:44:40.059Z
Learning: Applies to web/** : Use Node.js 22+ and npm for web dashboard; all dependencies in `web/package.json` (React 19, react-router, shadcn/ui, Radix UI, Tailwind CSS 4, Zustand, Recharts, Framer Motion, Axios, Lucide React, Geist fonts, Storybook 10, Vitest, ESLint, fast-check, etc.)
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-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)
📚 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/org/build-org-tree.ts
🔇 Additional comments (13)
web/src/pages/org/layout.ts (5)

1-16: LGTM!

Imports and type definitions are appropriate. Constants for default dimensions and padding are well-chosen defaults for org chart layout.


35-42: Grid fallback for department-only layouts looks correct.

When no leaf (agent) nodes exist, placing all nodes on a 3-column grid with preserved styles prevents overlapping. This addresses the prior concern about department-only scenarios.


44-75: Dagre graph construction and coordinate conversion are correct.

Leaf nodes are properly separated from department groups, edges are filtered to only include valid node pairs, and dagre center coordinates are correctly converted to React Flow top-left positions.


100-136: Group bounding box calculation and child position adjustment are correct.

Padding and header height offsets are properly applied, and child positions are updated immutably via positionedLeafMap.set().


138-139: Return combines groups and positioned leaves correctly.

web/src/pages/org/build-org-tree.ts (8)

1-5: LGTM!

Imports are appropriate and use path aliases as expected.


6-32: Well-structured node data interfaces.

The interfaces correctly define the data shape for each node type. Using null for optional health/task/cost fields allows the UI to distinguish "unknown/loading" from "zero" values. The [key: string]: unknown index signature satisfies React Flow's data typing requirements.


34-49: Seniority ranking is well-defined.

The SENIORITY_RANK mapping covers the expected levels and seniorityOf returns -1 for unknown levels, providing safe fallback behavior.


68-97: Agent filtering, grouping, and health integration are correct.

Terminated agents are properly excluded. The activeCount calculation correctly uses resolveRuntimeStatus to determine runtime state. Missing health data correctly defaults to null (lines 108, 111, 112) rather than falsely healthy values.


119-129: Team membership logic correctly prevents overwrites.

The !teamMemberSet.has(member.id) check at line 125 ensures the first team assignment wins if an agent appears in multiple teams, preventing silent overwrites.


131-177: Agent node creation and edge generation are correct.

CEO nodes receive the extended data with companyName. The edge creation logic properly handles:

  • Team members → team lead edges
  • Non-team agents → department head edges
  • CEO is excluded from self-referential edges

179-193: CEO-to-head edge deduplication is properly handled.

The alreadyConnected check prevents duplicate edges when a department head might already be connected via team structure.


198-231: Helper functions are well-documented and correct.

Tiebreaker behavior is clearly documented in the JSDoc comments for both findHighestSeniority and findCeo. The findDepartmentHead function correctly passes members directly (without unnecessary spread) when ceo is null, as that array is only read by findHighestSeniority.

@socket-security
Copy link
Copy Markdown

socket-security bot commented Mar 27, 2026

All alerts resolved. Learn more about Socket for GitHub.

This PR previously contained dependency changes with security issues that have been resolved, removed, or ignored.

View full report

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 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/pages/org/layout.ts`:
- Around line 35-40: The layout code that maps department group nodes (the
branch using leafNodes.length === 0 and the other empty-group branch) sets
style.height to 100 which conflicts with DepartmentGroupNode.tsx's rendered
min-h-[120px], causing bounds/fitView to be 20px short; update both mapping
branches (the nodes.map that returns { ...n, position: ..., style: { ...n.style,
width: 200, height: 100 } } and the other empty-group mapping) to use the
rendered empty-group height (height: 120 or otherwise derive the min height used
by DepartmentGroupNode) so the Flow measurements match the component's min
height.
- Around line 29-33: The dagre spacing doesn't account for department chrome
(40px side padding and 40px header), so compute effective separators after
detecting group nodes and increase/clamp them: after const groupNodes =
nodes.filter((n) => n.type === 'department') and const leafNodes = ..., if
groupNodes.length > 0 then bump horizontal spacing by the side chrome (e.g.,
nodeSep = Math.max(nodeSep, nodeSep + 80) or more simply nodeSep += 80) and bump
vertical spacing by the header chrome (e.g., rankSep = Math.max(rankSep, rankSep
+ 40) or rankSep += 40) so boxed departments cannot overlap; apply the same
adjustment where separators are set elsewhere noted (the other occurrences
around the file).
🪄 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: 50c6baf9-1125-4b91-be2b-e392cb19cadb

📥 Commits

Reviewing files that changed from the base of the PR and between ad73997 and 9c40a7d.

📒 Files selected for processing (1)
  • web/src/pages/org/layout.ts
📜 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: Build Sandbox
  • GitHub Check: Dependency Review
  • GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Use TypeScript 6+ with paths for module resolution (remove deprecated baseUrl); esModuleInterop is always true
In TypeScript, strict defaults to true and types defaults to []; do not auto-discover @types/* — must explicitly list needed types

Files:

  • web/src/pages/org/layout.ts
web/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

web/src/**/*.{ts,tsx}: Use React 19 with TypeScript 6+ in web dashboard; enforce design tokens (no hardcoded colors, fonts, spacing) and reuse components from web/src/components/ui/
Always reuse existing components from web/src/components/ui/ (StatusBadge, MetricCard, Sparkline, SectionCard, AgentCard, DeptHealthBar, ProgressGauge, StatPill, Avatar, Button, Toast, Skeleton, EmptyState, ErrorBoundary, ConfirmDialog, CommandPalette, InlineEdit, AnimatedPresence, StaggerGroup/StaggerItem) before creating new ones
Use design tokens exclusively in web components: Tailwind semantic classes (text-foreground, bg-card, text-accent, text-success, bg-danger, etc.) or CSS variables (var(--so-accent)); never hardcode hex values or pixel spacing
Use font-sans or font-mono (Geist tokens) in web components; never set fontFamily directly
Use density-aware spacing tokens in web components (p-card, gap-section-gap, gap-grid-gap) or standard Tailwind spacing; never hardcode pixel values for layout spacing
Use shadow and border token variables in web components (var(--so-shadow-card-hover), border-border, border-bright); never hardcode shadow or border styles
In React components, import cn from @/lib/utils for conditional class merging; never concatenate class strings directly
Do not recreate status dots inline; use <StatusBadge> component
Do not build card-with-header layouts from scratch; use <SectionCard> component
Do not create metric displays with text-metric font-bold; use <MetricCard> component
Do not render initials circles manually; use <Avatar> component
Do not create complex (>8 line) JSX inside .map() blocks; extract to a shared component

Files:

  • web/src/pages/org/layout.ts
web/src/pages/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use React Router with lazy-loaded page components (one per route); place page-scoped sub-components in pages/<page-name>/ subdirectories

Files:

  • web/src/pages/org/layout.ts
web/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use ESLint with @eslint-react/eslint-plugin and eslint-plugin-security in web dashboard

Files:

  • web/src/pages/org/layout.ts
web/**

📄 CodeRabbit inference engine (CLAUDE.md)

Use Node.js 22+ and npm for web dashboard; all dependencies in web/package.json (React 19, react-router, shadcn/ui, Radix UI, Tailwind CSS 4, Zustand, Recharts, Framer Motion, Axios, Lucide React, Geist fonts, Storybook 10, Vitest, ESLint, fast-check, etc.)

Files:

  • web/src/pages/org/layout.ts
🧠 Learnings (1)
📓 Common learnings
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/).
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T09:44:40.059Z
Learning: Applies to web/** : Use Node.js 22+ and npm for web dashboard; all dependencies in `web/package.json` (React 19, react-router, shadcn/ui, Radix UI, Tailwind CSS 4, Zustand, Recharts, Framer Motion, Axios, Lucide React, Geist fonts, Storybook 10, Vitest, ESLint, fast-check, etc.)
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-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)

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 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/pages/org/layout.ts`:
- Line 30: The fallback branches ignore the destructured direction variable and
always render a top-to-bottom grid; update the department-only and
empty-department JSX branches to honor direction by using the direction value
when building the grid (e.g., conditionally set gridAutoFlow/gridTemplateColumns
vs gridTemplateRows or swap CSS classes) so applyDagreLayout(..., { direction:
'LR' }) produces a left-to-right layout; locate and update the branches that
render the empty department and department-only grids (referencing the direction
constant) to choose column-oriented styles when direction === 'LR' and
row-oriented styles when direction === 'TB'.
🪄 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: 6358bdf8-9a96-412e-89a8-f8f625cc2590

📥 Commits

Reviewing files that changed from the base of the PR and between 9c40a7d and 3f46cbc.

📒 Files selected for processing (1)
  • web/src/pages/org/layout.ts
📜 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 Web
  • GitHub Check: Build Backend
  • GitHub Check: Build Sandbox
  • GitHub Check: Dependency Review
  • GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Use TypeScript 6+ with paths for module resolution (remove deprecated baseUrl); esModuleInterop is always true
In TypeScript, strict defaults to true and types defaults to []; do not auto-discover @types/* — must explicitly list needed types

Files:

  • web/src/pages/org/layout.ts
web/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

web/src/**/*.{ts,tsx}: Use React 19 with TypeScript 6+ in web dashboard; enforce design tokens (no hardcoded colors, fonts, spacing) and reuse components from web/src/components/ui/
Always reuse existing components from web/src/components/ui/ (StatusBadge, MetricCard, Sparkline, SectionCard, AgentCard, DeptHealthBar, ProgressGauge, StatPill, Avatar, Button, Toast, Skeleton, EmptyState, ErrorBoundary, ConfirmDialog, CommandPalette, InlineEdit, AnimatedPresence, StaggerGroup/StaggerItem) before creating new ones
Use design tokens exclusively in web components: Tailwind semantic classes (text-foreground, bg-card, text-accent, text-success, bg-danger, etc.) or CSS variables (var(--so-accent)); never hardcode hex values or pixel spacing
Use font-sans or font-mono (Geist tokens) in web components; never set fontFamily directly
Use density-aware spacing tokens in web components (p-card, gap-section-gap, gap-grid-gap) or standard Tailwind spacing; never hardcode pixel values for layout spacing
Use shadow and border token variables in web components (var(--so-shadow-card-hover), border-border, border-bright); never hardcode shadow or border styles
In React components, import cn from @/lib/utils for conditional class merging; never concatenate class strings directly
Do not recreate status dots inline; use <StatusBadge> component
Do not build card-with-header layouts from scratch; use <SectionCard> component
Do not create metric displays with text-metric font-bold; use <MetricCard> component
Do not render initials circles manually; use <Avatar> component
Do not create complex (>8 line) JSX inside .map() blocks; extract to a shared component

Files:

  • web/src/pages/org/layout.ts
web/src/pages/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use React Router with lazy-loaded page components (one per route); place page-scoped sub-components in pages/<page-name>/ subdirectories

Files:

  • web/src/pages/org/layout.ts
web/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use ESLint with @eslint-react/eslint-plugin and eslint-plugin-security in web dashboard

Files:

  • web/src/pages/org/layout.ts
web/**

📄 CodeRabbit inference engine (CLAUDE.md)

Use Node.js 22+ and npm for web dashboard; all dependencies in web/package.json (React 19, react-router, shadcn/ui, Radix UI, Tailwind CSS 4, Zustand, Recharts, Framer Motion, Axios, Lucide React, Geist fonts, Storybook 10, Vitest, ESLint, fast-check, etc.)

Files:

  • web/src/pages/org/layout.ts
🧠 Learnings (2)
📓 Common learnings
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/).
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T09:44:40.059Z
Learning: Applies to web/** : Use Node.js 22+ and npm for web dashboard; all dependencies in `web/package.json` (React 19, react-router, shadcn/ui, Radix UI, Tailwind CSS 4, Zustand, Recharts, Framer Motion, Axios, Lucide React, Geist fonts, Storybook 10, Vitest, ESLint, fast-check, etc.)
📚 Learning: 2026-03-27T09:44:40.059Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T09:44:40.059Z
Learning: Applies to web/src/**/*.{ts,tsx} : Use density-aware spacing tokens in web components (`p-card`, `gap-section-gap`, `gap-grid-gap`) or standard Tailwind spacing; never hardcode pixel values for layout spacing

Applied to files:

  • web/src/pages/org/layout.ts
🔇 Additional comments (1)
web/src/pages/org/layout.ts (1)

16-16: Good alignment between empty-group sizing and dagre spacing.

Matching EMPTY_GROUP_HEIGHT to the rendered department minimum and reserving extra separator budget for group chrome should prevent the earlier clipping/overlap cases.

Also applies to: 37-41

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 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/pages/org/layout.ts`:
- Around line 101-142: The map callback for positionedGroups mixes pure
computation with a side-effect that mutates positionedLeafMap (see
groupNodes.map and the loop that calls positionedLeafMap.set), harming
readability; refactor by first computing and returning group objects
(groupX/groupY/groupWidth/groupHeight and children list) inside the map without
touching positionedLeafMap, then in a separate pass iterate the computed groups
and adjust child positions (or build a new positionedLeafMap) using the saved
groupX/groupY values so the map remains a pure transformation and mutations are
isolated to a clearly named function or loop.
🪄 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: ee0ae3f9-35cc-4db7-ab42-ec186db3cb11

📥 Commits

Reviewing files that changed from the base of the PR and between 3f46cbc and 19f0834.

📒 Files selected for processing (5)
  • web/src/__tests__/App.test.tsx
  • web/src/__tests__/pages/DashboardPage.test.tsx
  • web/src/__tests__/pages/dashboard/ActivityFeed.test.tsx
  • web/src/__tests__/utils/errors.property.test.ts
  • web/src/pages/org/layout.ts
📜 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). (7)
  • GitHub Check: Build Web
  • GitHub Check: Build Backend
  • GitHub Check: Dashboard Test
  • GitHub Check: Build Sandbox
  • GitHub Check: Dependency Review
  • GitHub Check: Analyze (go)
  • GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Use TypeScript 6+ with paths for module resolution (remove deprecated baseUrl); esModuleInterop is always true
In TypeScript, strict defaults to true and types defaults to []; do not auto-discover @types/* — must explicitly list needed types

Files:

  • web/src/__tests__/App.test.tsx
  • web/src/__tests__/pages/dashboard/ActivityFeed.test.tsx
  • web/src/__tests__/pages/DashboardPage.test.tsx
  • web/src/__tests__/utils/errors.property.test.ts
  • web/src/pages/org/layout.ts
web/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

web/src/**/*.{ts,tsx}: Use React 19 with TypeScript 6+ in web dashboard; enforce design tokens (no hardcoded colors, fonts, spacing) and reuse components from web/src/components/ui/
Always reuse existing components from web/src/components/ui/ (StatusBadge, MetricCard, Sparkline, SectionCard, AgentCard, DeptHealthBar, ProgressGauge, StatPill, Avatar, Button, Toast, Skeleton, EmptyState, ErrorBoundary, ConfirmDialog, CommandPalette, InlineEdit, AnimatedPresence, StaggerGroup/StaggerItem) before creating new ones
Use design tokens exclusively in web components: Tailwind semantic classes (text-foreground, bg-card, text-accent, text-success, bg-danger, etc.) or CSS variables (var(--so-accent)); never hardcode hex values or pixel spacing
Use font-sans or font-mono (Geist tokens) in web components; never set fontFamily directly
Use density-aware spacing tokens in web components (p-card, gap-section-gap, gap-grid-gap) or standard Tailwind spacing; never hardcode pixel values for layout spacing
Use shadow and border token variables in web components (var(--so-shadow-card-hover), border-border, border-bright); never hardcode shadow or border styles
In React components, import cn from @/lib/utils for conditional class merging; never concatenate class strings directly
Do not recreate status dots inline; use <StatusBadge> component
Do not build card-with-header layouts from scratch; use <SectionCard> component
Do not create metric displays with text-metric font-bold; use <MetricCard> component
Do not render initials circles manually; use <Avatar> component
Do not create complex (>8 line) JSX inside .map() blocks; extract to a shared component

Files:

  • web/src/__tests__/App.test.tsx
  • web/src/__tests__/pages/dashboard/ActivityFeed.test.tsx
  • web/src/__tests__/pages/DashboardPage.test.tsx
  • web/src/__tests__/utils/errors.property.test.ts
  • web/src/pages/org/layout.ts
web/src/__tests__/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

web/src/__tests__/**/*.{ts,tsx}: Use fast-check for property-based testing in React; use fc.assert and fc.property
Use Vitest for React unit testing with coverage scoped to files changed vs origin/main

Files:

  • web/src/__tests__/App.test.tsx
  • web/src/__tests__/pages/dashboard/ActivityFeed.test.tsx
  • web/src/__tests__/pages/DashboardPage.test.tsx
  • web/src/__tests__/utils/errors.property.test.ts
web/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use ESLint with @eslint-react/eslint-plugin and eslint-plugin-security in web dashboard

Files:

  • web/src/__tests__/App.test.tsx
  • web/src/__tests__/pages/dashboard/ActivityFeed.test.tsx
  • web/src/__tests__/pages/DashboardPage.test.tsx
  • web/src/__tests__/utils/errors.property.test.ts
  • web/src/pages/org/layout.ts
web/**

📄 CodeRabbit inference engine (CLAUDE.md)

Use Node.js 22+ and npm for web dashboard; all dependencies in web/package.json (React 19, react-router, shadcn/ui, Radix UI, Tailwind CSS 4, Zustand, Recharts, Framer Motion, Axios, Lucide React, Geist fonts, Storybook 10, Vitest, ESLint, fast-check, etc.)

Files:

  • web/src/__tests__/App.test.tsx
  • web/src/__tests__/pages/dashboard/ActivityFeed.test.tsx
  • web/src/__tests__/pages/DashboardPage.test.tsx
  • web/src/__tests__/utils/errors.property.test.ts
  • web/src/pages/org/layout.ts
web/src/pages/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use React Router with lazy-loaded page components (one per route); place page-scoped sub-components in pages/<page-name>/ subdirectories

Files:

  • web/src/pages/org/layout.ts
🧠 Learnings (6)
📓 Common learnings
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/).
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T09:44:40.059Z
Learning: Applies to web/** : Use Node.js 22+ and npm for web dashboard; all dependencies in `web/package.json` (React 19, react-router, shadcn/ui, Radix UI, Tailwind CSS 4, Zustand, Recharts, Framer Motion, Axios, Lucide React, Geist fonts, Storybook 10, Vitest, ESLint, fast-check, etc.)
📚 Learning: 2026-03-27T09:44:40.059Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T09:44:40.059Z
Learning: Applies to web/src/__tests__/**/*.{ts,tsx} : Use Vitest for React unit testing with coverage scoped to files changed vs origin/main

Applied to files:

  • web/src/__tests__/App.test.tsx
  • web/src/__tests__/pages/dashboard/ActivityFeed.test.tsx
  • web/src/__tests__/pages/DashboardPage.test.tsx
  • web/src/__tests__/utils/errors.property.test.ts
📚 Learning: 2026-03-27T09:44:40.059Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T09:44:40.059Z
Learning: Applies to web/src/__tests__/**/*.{ts,tsx} : Use fast-check for property-based testing in React; use `fc.assert` and `fc.property`

Applied to files:

  • web/src/__tests__/App.test.tsx
  • web/src/__tests__/pages/dashboard/ActivityFeed.test.tsx
  • web/src/__tests__/pages/DashboardPage.test.tsx
  • web/src/__tests__/utils/errors.property.test.ts
📚 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/src/__tests__/pages/dashboard/ActivityFeed.test.tsx
  • web/src/__tests__/pages/DashboardPage.test.tsx
  • web/src/__tests__/utils/errors.property.test.ts
📚 Learning: 2026-03-27T09:44:40.059Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T09:44:40.059Z
Learning: Applies to web/src/**/*.{ts,tsx} : Use React 19 with TypeScript 6+ in web dashboard; enforce design tokens (no hardcoded colors, fonts, spacing) and reuse components from `web/src/components/ui/`

Applied to files:

  • web/src/__tests__/pages/dashboard/ActivityFeed.test.tsx
  • web/src/__tests__/pages/DashboardPage.test.tsx
📚 Learning: 2026-03-27T09:44:40.059Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T09:44:40.059Z
Learning: Applies to web/src/**/*.{ts,tsx} : Use density-aware spacing tokens in web components (`p-card`, `gap-section-gap`, `gap-grid-gap`) or standard Tailwind spacing; never hardcode pixel values for layout spacing

Applied to files:

  • web/src/pages/org/layout.ts
🔇 Additional comments (11)
web/src/__tests__/App.test.tsx (1)

59-84: LGTM!

The reformatted test with an explicit 10-second timeout is a sound approach to address flakiness from lazy-loaded modules during concurrent test runs. The test-level timeout (10s) correctly exceeds the waitFor timeout (5s), ensuring the assertion has room to complete before the test itself times out.

web/src/__tests__/pages/DashboardPage.test.tsx (3)

64-73: Clean refactoring from dynamic to static import.

The static import after vi.mock is the correct pattern—Vitest hoists mock declarations, so the mock is applied before the import executes. Removing the async wrapper from renderDashboard() simplifies all test cases appropriately.


85-89: Good switch to label-based query.

Using getByLabelText('Loading dashboard') is more specific than getByRole('status') and produces clearer test failure messages. This also aligns with the pattern established in the new OrgChartPage tests and correctly targets the aria-label attribute in DashboardSkeleton.


126-132: Correct negative assertion pattern.

Using queryByLabelText for the "does not exist" assertion is the right approach—query* methods return null instead of throwing, making them suitable for negative assertions.

web/src/__tests__/utils/errors.property.test.ts (3)

2-14: Vitest axios mock setup is solid and deterministic.

Using vi.mock('axios', ...) here is a good fix for async-leak noise, and exposing both default.isAxiosError and isAxiosError keeps compatibility with common import styles.

As per coding guidelines, “Use Vitest for React unit testing with coverage scoped to files changed vs origin/main.”


16-25: makeFakeAxiosError correctly mirrors the error shape under test.

The helper includes the exact fields consumed by getErrorMessage, while avoiding dependence on real AxiosError internals in the test environment.


44-44: Property assertion remains strong with the fake error object.

Switching to makeFakeAxiosError keeps the 5xx non-leak invariant intact without weakening the property-based test.

As per coding guidelines, “Use fast-check for property-based testing in React; use fc.assert and fc.property.”

web/src/__tests__/pages/dashboard/ActivityFeed.test.tsx (1)

54-54: This change is part of a deliberate CI flakiness fix and is appropriately justified.

The numRuns: 10 reduction is intentional, as indicated by the commit message "fix: honor layout direction in fallback branches and fix CI test flakes." For this simple, deterministic property—which verifies ActivityFeed caps items at 10—10 runs provides sufficient coverage of edge cases (count 0, 1–9, 10, 11+, 50) without causing unnecessary test delays.

			> Likely an incorrect or invalid review comment.
web/src/pages/org/layout.ts (3)

1-16: Well-structured constants and type definitions.

The constants correctly match the component constraints: EMPTY_GROUP_HEIGHT = 120 aligns with DepartmentGroupNode's min-h-[120px], and DEFAULT_NODE_WIDTH = 160 is appropriately centered within the responsive CSS range (min-w-[140px] max-w-[180px]).


43-53: Direction-aware grid fallback is correctly implemented.

The no-leaf-nodes branch now properly respects the direction option with the isLR conditional, and preserves existing styles with spread operator.


151-152: Correct node ordering for React Flow containment.

Returning groups before leaves ensures proper z-index stacking in React Flow, where parent group nodes must precede their children.

@Aureliolo Aureliolo force-pushed the feat/org-chart-page branch from 70505b9 to 551b32b Compare March 27, 2026 12:47
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

🤖 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/__tests__/pages/dashboard/ActivityFeed.test.tsx`:
- Line 54: The test lowered the randomized iteration count by changing the
numRuns value in ActivityFeed.test.tsx, which weakens coverage; restore stronger
coverage by making numRuns environment-aware (e.g., use process.env.CI or a
TEST_RUNS env var) so CI uses 20 while local runs can default to 10, and update
the numRuns reference in the test (the variable used in the ActivityFeed test
block) to read from that env-aware value.

In `@web/src/pages/org/AgentNode.stories.tsx`:
- Line 11: The story contains a div with hardcoded inline style width/height in
AgentNode.stories.tsx; replace that inline style on the container div with the
appropriate Tailwind sizing utility classes (use the nearest standard Tailwind
classes or your design system tokens, e.g., w-*/h-* equivalents) so the
component uses density-aware/tailwind sizing rather than pixel values; update
the JSX div (the container around the story preview) to use className with
Tailwind sizing utilities instead of style={{ width: 400, height: 200 }}.

In `@web/src/pages/org/layout.ts`:
- Around line 60-65: The dagre layout currently uses placeholder sizes
(DEFAULT_NODE_WIDTH/DEFAULT_NODE_HEIGHT) when node.measured is undefined,
yielding an initial layout that mismatches rendered nodes; update the flow so
that after React Flow measures nodes (i.e., when measured.width/height become
available on leafNodes) you recompute the layout and call g.setNode with the
real measured dimensions and re-run the dagre layout pass (or alternatively
enforce fixed dimensions inside the node component), ensuring you trigger the
layout update from the same routine that uses leafNodes and g.setNode so nodes
are laid out with actual sizes instead of placeholders.

In `@web/src/pages/org/NodeContextMenu.tsx`:
- Around line 46-61: The handleClick inside the useEffect uses (e.target as
HTMLElement) when calling menuRef.current.contains, which can be wrong for
non-HTMLElement nodes (SVG, Text, etc.); change the cast to Node (e.g., e.target
as Node) or otherwise ensure the value passed to menuRef.current.contains is
typed as Node | null so contains receives the correct type; update the
handleClick function in NodeContextMenu (referencing useEffect, handleClick,
menuRef, onClose) accordingly.

In `@web/src/pages/org/OrgChartToolbar.stories.tsx`:
- Around line 18-25: The Storybook meta currently sets component:
InteractiveToolbar which causes autodocs to pick up the wrapper instead of the
real component; update the meta to set component: OrgChartToolbar (or keep
InteractiveToolbar but add a render that returns
<InteractiveToolbar><OrgChartToolbar .../></InteractiveToolbar>) so autodocs
reflect OrgChartToolbar's props—modify the meta object (symbol: meta) and the
entries for component/render, referencing InteractiveToolbar and OrgChartToolbar
to ensure the correct API is documented.

In `@web/src/pages/OrgChartPage.tsx`:
- Line 264: Replace the intermediate CSS token with the canonical SynthOrg
token: in the Background component usage (Background color="var(--color-border)"
gap={24} size={1}), change the color prop to use var(--so-border) instead of
var(--color-border) so the component uses the recommended design token directly.

In `@web/src/stores/company.ts`:
- Around line 49-55: The WebSocket handler updateFromWsEvent calls the async
fetchCompanyData via useCompanyStore.getState().fetchCompanyData() without
awaiting or catching errors; change this to either await the call (making
updateFromWsEvent async) or attach a .catch(...) to the returned promise and log
the error (e.g., console.error or your app logger) so fetchCompanyData failures
aren’t silently swallowed; update the invocation accordingly in
updateFromWsEvent to ensure errors are visible.
🪄 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: 0f3c1ae5-ac27-415d-9caf-75e62c4634f4

📥 Commits

Reviewing files that changed from the base of the PR and between 19f0834 and 551b32b.

⛔ Files ignored due to path filters (1)
  • web/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (39)
  • CLAUDE.md
  • web/package.json
  • web/src/__tests__/App.test.tsx
  • web/src/__tests__/pages/DashboardPage.test.tsx
  • web/src/__tests__/pages/dashboard/ActivityFeed.test.tsx
  • web/src/__tests__/pages/org/DepartmentStatsBar.test.tsx
  • web/src/__tests__/pages/org/NodeContextMenu.test.tsx
  • web/src/__tests__/pages/org/OrgChartPage.test.tsx
  • web/src/__tests__/pages/org/OrgChartSkeleton.test.tsx
  • web/src/__tests__/pages/org/OrgChartToolbar.test.tsx
  • web/src/__tests__/pages/org/build-org-tree.test.ts
  • web/src/__tests__/pages/org/layout.test.ts
  • web/src/__tests__/pages/org/status-mapping.test.ts
  • web/src/__tests__/stores/agents.test.ts
  • web/src/__tests__/stores/company.test.ts
  • web/src/__tests__/utils/errors.property.test.ts
  • web/src/hooks/useOrgChartData.ts
  • web/src/pages/OrgChartPage.tsx
  • web/src/pages/org/AgentNode.stories.tsx
  • web/src/pages/org/AgentNode.tsx
  • web/src/pages/org/CeoNode.stories.tsx
  • web/src/pages/org/CeoNode.tsx
  • web/src/pages/org/DepartmentGroupNode.stories.tsx
  • web/src/pages/org/DepartmentGroupNode.tsx
  • web/src/pages/org/DepartmentStatsBar.stories.tsx
  • web/src/pages/org/DepartmentStatsBar.tsx
  • web/src/pages/org/HierarchyEdge.tsx
  • web/src/pages/org/NodeContextMenu.stories.tsx
  • web/src/pages/org/NodeContextMenu.tsx
  • web/src/pages/org/OrgChartSkeleton.stories.tsx
  • web/src/pages/org/OrgChartSkeleton.tsx
  • web/src/pages/org/OrgChartToolbar.stories.tsx
  • web/src/pages/org/OrgChartToolbar.tsx
  • web/src/pages/org/build-org-tree.ts
  • web/src/pages/org/layout.ts
  • web/src/pages/org/status-mapping.ts
  • web/src/stores/agents.ts
  • web/src/stores/company.ts
  • web/src/styles/global.css
📜 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 Backend
  • GitHub Check: Build Web
  • GitHub Check: Build Sandbox
  • GitHub Check: Dependency Review
  • GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (3)
web/src/**/*.{tsx,ts}

📄 CodeRabbit inference engine (CLAUDE.md)

web/src/**/*.{tsx,ts}: Always reuse existing components from web/src/components/ui/ before creating new ones. Check the required component inventory (StatusBadge, MetricCard, Sparkline, SectionCard, AgentCard, DeptHealthBar, ProgressGauge, StatPill, Avatar, Button, Toast, Skeleton, EmptyState, ErrorBoundary, ConfirmDialog, CommandPalette, InlineEdit, AnimatedPresence, StaggerGroup, TaskStatusIndicator, PriorityBadge)
Use Tailwind semantic classes (text-foreground, bg-card, text-accent, text-success, bg-danger) or CSS variables (var(--so-*)) for colors; never hardcode hex values
Use font-sans or font-mono for typography (maps to Geist tokens); never set fontFamily directly
Use density-aware spacing tokens (p-card, gap-section-gap, gap-grid-gap) or standard Tailwind spacing; never hardcode pixel values for layout spacing
Use token variables for shadows and borders (var(--so-shadow-card-hover), border-border, border-bright)
Do NOT recreate status dots inline -- use <StatusBadge>; do NOT build card-with-header layouts from scratch -- use <SectionCard>; do NOT create metric displays inline -- use <MetricCard>; do NOT render initials circles manually -- use <Avatar>; do NOT create complex (>8 line) JSX inside .map() -- extract to shared component
TypeScript 6.0: remove baseUrl (deprecated, will stop working in TS 7); esModuleInterop always true (cannot be set false); types defaults to [] (must explicitly list needed types); DOM.Iterable merged into DOM; moduleResolution: 'classic' and 'node10' removed (use 'bundler' or 'nodenext'); strict defaults to true
Storybook 10 is ESM-only; @storybook/addon-essentials, @storybook/addon-interactions, @storybook/test, @storybook/blocks no longer published (features built into core storybook); @storybook/addon-docs must be installed separately if using tags: ['autodocs']

Files:

  • web/src/__tests__/App.test.tsx
  • web/src/__tests__/pages/dashboard/ActivityFeed.test.tsx
  • web/src/__tests__/pages/org/OrgChartSkeleton.test.tsx
  • web/src/__tests__/pages/DashboardPage.test.tsx
  • web/src/__tests__/pages/org/OrgChartToolbar.test.tsx
  • web/src/__tests__/pages/org/DepartmentStatsBar.test.tsx
  • web/src/pages/org/OrgChartSkeleton.tsx
  • web/src/__tests__/pages/org/layout.test.ts
  • web/src/pages/org/HierarchyEdge.tsx
  • web/src/pages/org/OrgChartSkeleton.stories.tsx
  • web/src/pages/org/OrgChartToolbar.stories.tsx
  • web/src/__tests__/pages/org/status-mapping.test.ts
  • web/src/__tests__/utils/errors.property.test.ts
  • web/src/pages/org/DepartmentStatsBar.tsx
  • web/src/__tests__/stores/agents.test.ts
  • web/src/stores/agents.ts
  • web/src/__tests__/pages/org/OrgChartPage.test.tsx
  • web/src/pages/org/DepartmentGroupNode.tsx
  • web/src/__tests__/stores/company.test.ts
  • web/src/pages/org/CeoNode.tsx
  • web/src/pages/org/DepartmentGroupNode.stories.tsx
  • web/src/pages/org/OrgChartToolbar.tsx
  • web/src/pages/org/status-mapping.ts
  • web/src/pages/org/NodeContextMenu.tsx
  • web/src/pages/org/AgentNode.tsx
  • web/src/pages/org/NodeContextMenu.stories.tsx
  • web/src/pages/org/DepartmentStatsBar.stories.tsx
  • web/src/pages/org/AgentNode.stories.tsx
  • web/src/stores/company.ts
  • web/src/__tests__/pages/org/NodeContextMenu.test.tsx
  • web/src/hooks/useOrgChartData.ts
  • web/src/__tests__/pages/org/build-org-tree.test.ts
  • web/src/pages/OrgChartPage.tsx
  • web/src/pages/org/build-org-tree.ts
  • web/src/pages/org/layout.ts
  • web/src/pages/org/CeoNode.stories.tsx
**/*.md

📄 CodeRabbit inference engine (CLAUDE.md)

Markdown trailing-whitespace removal and end-of-file fixing enforced by pre-commit hooks

Files:

  • CLAUDE.md
web/src/**/*.stories.tsx

📄 CodeRabbit inference engine (CLAUDE.md)

Storybook 10: use definePreview from @storybook/react-vite for type-safe config; import from storybook/test (not @storybook/test) and storybook/actions (not @storybook/addon-actions); use parameters.backgrounds.options (object keyed by name) + initialGlobals.backgrounds.value; use parameters.a11y.test: 'error' | 'todo' | 'off' for accessibility testing

Files:

  • web/src/pages/org/OrgChartSkeleton.stories.tsx
  • web/src/pages/org/OrgChartToolbar.stories.tsx
  • web/src/pages/org/DepartmentGroupNode.stories.tsx
  • web/src/pages/org/NodeContextMenu.stories.tsx
  • web/src/pages/org/DepartmentStatsBar.stories.tsx
  • web/src/pages/org/AgentNode.stories.tsx
  • web/src/pages/org/CeoNode.stories.tsx
🧠 Learnings (25)
📓 Common learnings
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/).
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to docs/design/*.md : Design spec pages: 7 pages in `docs/design/` — index, agents, organization, communication, engine, memory, operations
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-16T06:24:56.341Z
Learning: Applies to docs/design/**/*.md : Design specification pages in `docs/design/` must be consulted before implementing features (7 pages: index, agents, organization, communication, engine, memory, operations)
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).
📚 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/src/__tests__/pages/dashboard/ActivityFeed.test.tsx
  • web/src/__tests__/pages/org/OrgChartSkeleton.test.tsx
  • CLAUDE.md
  • web/src/__tests__/pages/DashboardPage.test.tsx
  • web/src/__tests__/pages/org/OrgChartToolbar.test.tsx
  • web/src/__tests__/pages/org/DepartmentStatsBar.test.tsx
  • web/src/__tests__/pages/org/layout.test.ts
  • web/src/__tests__/pages/org/status-mapping.test.ts
  • web/src/__tests__/utils/errors.property.test.ts
  • web/src/__tests__/stores/agents.test.ts
  • web/src/__tests__/pages/org/OrgChartPage.test.tsx
  • web/src/__tests__/stores/company.test.ts
  • web/src/__tests__/pages/org/NodeContextMenu.test.tsx
  • web/src/__tests__/pages/org/build-org-tree.test.ts
📚 Learning: 2026-03-27T12:41:55.315Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T12:41:55.315Z
Learning: Applies to web/src/**/*.stories.tsx : Storybook 10: use `definePreview` from `storybook/react-vite` for type-safe config; import from `storybook/test` (not `storybook/test`) and `storybook/actions` (not `storybook/addon-actions`); use `parameters.backgrounds.options` (object keyed by name) + `initialGlobals.backgrounds.value`; use `parameters.a11y.test: 'error' | 'todo' | 'off'` for accessibility testing

Applied to files:

  • web/src/__tests__/pages/org/OrgChartSkeleton.test.tsx
  • web/src/__tests__/pages/DashboardPage.test.tsx
  • web/src/__tests__/pages/org/OrgChartToolbar.test.tsx
  • web/src/pages/org/OrgChartSkeleton.stories.tsx
  • web/src/pages/org/OrgChartToolbar.stories.tsx
  • web/src/__tests__/pages/org/OrgChartPage.test.tsx
  • web/src/__tests__/stores/company.test.ts
  • web/src/pages/org/DepartmentGroupNode.stories.tsx
  • web/src/pages/org/NodeContextMenu.stories.tsx
  • web/src/pages/org/DepartmentStatsBar.stories.tsx
  • web/src/pages/org/AgentNode.stories.tsx
  • web/src/__tests__/pages/org/NodeContextMenu.test.tsx
  • web/src/pages/org/CeoNode.stories.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: 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:

  • CLAUDE.md
  • web/package.json
📚 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:

  • CLAUDE.md
  • web/package.json
  • web/src/pages/org/CeoNode.tsx
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to src/synthorg/**/*.py : Package structure: src/synthorg/ organized as: api/ (REST+WebSocket, Litestar), auth/ (auth subpackage), backup/ (scheduled/manual backups), budget/ (cost tracking, CFO), cli/ (superseded by Go CLI), communication/ (message bus, meetings), config/ (YAML loading), core/ (domain models, resilience config), engine/ (orchestration, task state, coordination, approval gates, stagnation detection, context budget, compaction), hr/ (hiring, performance, promotion), memory/ (pluggable backend, Mem0, retrieval, consolidation), persistence/ (operational data, SQLite, settings), observability/ (logging, correlation, sinks), providers/ (LLM abstraction, LiteLLM, auth types, presets, runtime CRUD), settings/ (runtime-editable, typed definitions, encryption, config bridge), security/ (SecOps, rule engine, output scanning, progressive trust, autonomy levels), templates/ (company templates, personalities), tools/ (registry, built-in tools, git, sandbox, code_runner, MCP...

Applied to files:

  • CLAUDE.md
📚 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:

  • CLAUDE.md
  • web/src/__tests__/pages/org/DepartmentStatsBar.test.tsx
  • web/src/pages/org/OrgChartSkeleton.tsx
  • web/src/pages/OrgChartPage.tsx
  • web/src/pages/org/build-org-tree.ts
📚 Learning: 2026-03-27T12:41:55.315Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T12:41:55.315Z
Learning: Applies to web/src/components/ui/*.{tsx,ts} : When creating new shared UI components, place in `web/src/components/ui/` with kebab-case filename, create adjacent `.stories.tsx` with all states, export props as TypeScript interface, use design tokens exclusively (no hardcoded colors/fonts/spacing), import `cn` from `@/lib/utils` for conditional class merging

Applied to files:

  • CLAUDE.md
  • web/src/pages/org/OrgChartSkeleton.tsx
  • web/src/pages/org/OrgChartSkeleton.stories.tsx
  • web/src/pages/org/OrgChartToolbar.stories.tsx
  • web/src/pages/org/DepartmentGroupNode.tsx
  • web/src/pages/org/CeoNode.tsx
  • web/src/pages/org/DepartmentGroupNode.stories.tsx
  • web/src/pages/org/OrgChartToolbar.tsx
  • web/src/pages/org/AgentNode.tsx
  • web/src/pages/org/NodeContextMenu.stories.tsx
  • web/src/pages/org/DepartmentStatsBar.stories.tsx
  • web/src/pages/org/AgentNode.stories.tsx
  • web/src/pages/org/CeoNode.stories.tsx
📚 Learning: 2026-03-27T12:41:55.315Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T12:41:55.315Z
Learning: Applies to web/src/**/*.{tsx,ts} : Do NOT recreate status dots inline -- use `<StatusBadge>`; do NOT build card-with-header layouts from scratch -- use `<SectionCard>`; do NOT create metric displays inline -- use `<MetricCard>`; do NOT render initials circles manually -- use `<Avatar>`; do NOT create complex (>8 line) JSX inside `.map()` -- extract to shared component

Applied to files:

  • CLAUDE.md
  • web/src/__tests__/pages/DashboardPage.test.tsx
  • web/src/__tests__/pages/org/OrgChartToolbar.test.tsx
  • web/src/pages/org/OrgChartSkeleton.tsx
  • web/src/pages/org/OrgChartSkeleton.stories.tsx
  • web/src/pages/org/DepartmentStatsBar.tsx
  • web/src/pages/org/DepartmentGroupNode.tsx
  • web/src/pages/org/CeoNode.tsx
  • web/src/pages/org/DepartmentGroupNode.stories.tsx
  • web/src/pages/org/AgentNode.tsx
  • web/src/pages/org/DepartmentStatsBar.stories.tsx
  • web/src/hooks/useOrgChartData.ts
  • web/src/pages/OrgChartPage.tsx
  • web/src/pages/org/layout.ts
  • web/src/pages/org/CeoNode.stories.tsx
📚 Learning: 2026-03-27T12:41:55.315Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T12:41:55.315Z
Learning: Applies to web/src/**/*.{tsx,ts} : Always reuse existing components from `web/src/components/ui/` before creating new ones. Check the required component inventory (StatusBadge, MetricCard, Sparkline, SectionCard, AgentCard, DeptHealthBar, ProgressGauge, StatPill, Avatar, Button, Toast, Skeleton, EmptyState, ErrorBoundary, ConfirmDialog, CommandPalette, InlineEdit, AnimatedPresence, StaggerGroup, TaskStatusIndicator, PriorityBadge)

Applied to files:

  • CLAUDE.md
  • web/src/__tests__/pages/org/OrgChartToolbar.test.tsx
  • web/src/__tests__/pages/org/DepartmentStatsBar.test.tsx
  • web/src/pages/org/OrgChartSkeleton.tsx
  • web/src/pages/org/OrgChartSkeleton.stories.tsx
  • web/src/pages/org/DepartmentStatsBar.tsx
  • web/src/pages/org/DepartmentGroupNode.tsx
  • web/src/pages/org/CeoNode.tsx
  • web/src/pages/org/AgentNode.tsx
  • web/src/pages/org/DepartmentStatsBar.stories.tsx
  • web/src/__tests__/pages/org/NodeContextMenu.test.tsx
  • web/src/hooks/useOrgChartData.ts
  • web/src/pages/OrgChartPage.tsx
  • web/src/pages/org/build-org-tree.ts
📚 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 docs/** : Docs source in docs/ (Markdown, built with Zensical); design spec in docs/design/ (7 pages: index, agents, organization, communication, engine, memory, operations)

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-27T12:41:55.315Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T12:41:55.315Z
Learning: Applies to web/src/**/*.{tsx,ts} : Storybook 10 is ESM-only; storybook/addon-essentials, storybook/addon-interactions, storybook/test, storybook/blocks no longer published (features built into core `storybook`); storybook/addon-docs must be installed separately if using `tags: ['autodocs']`

Applied to files:

  • CLAUDE.md
  • web/src/pages/org/OrgChartSkeleton.stories.tsx
  • web/src/pages/org/OrgChartToolbar.stories.tsx
  • web/package.json
  • web/src/pages/org/DepartmentGroupNode.stories.tsx
  • web/src/pages/org/NodeContextMenu.stories.tsx
  • web/src/pages/org/DepartmentStatsBar.stories.tsx
  • web/src/pages/org/AgentNode.stories.tsx
  • web/src/__tests__/pages/org/NodeContextMenu.test.tsx
  • web/src/pages/org/CeoNode.stories.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: Applies to pyproject.toml : Dependencies: all versions use == in pyproject.toml. Groups: test (pytest + plugins, hypothesis), dev (includes test + ruff, mypy, pre-commit, commitizen, pip-audit). Required: mem0ai (Mem0 memory backend — the default and currently only backend). Install: uv sync installs everything (dev group is default).

Applied to files:

  • CLAUDE.md
📚 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: Go 1.26+ required; CLI dependencies in `cli/go.mod` (Cobra, charmbracelet/huh, charmbracelet/lipgloss, sigstore-go, go-containerregistry, go-tuf)

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: 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:

  • 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: Applies to go.mod : Maintain Go 1.26+ requirement. Dependencies: Cobra (CLI framework), charmbracelet/huh and charmbracelet/lipgloss (UI), sigstore-go (code signing), go-containerregistry (container image verification), go-tuf (TUF client for Sigstore).

Applied to files:

  • CLAUDE.md
📚 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: Applies to cli/go.mod : CLI uses Go 1.26+. Dependencies: Cobra, charmbracelet/huh, charmbracelet/lipgloss, sigstore-go, go-containerregistry, go-tuf

Applied to files:

  • CLAUDE.md
📚 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 cli/**/*.go : Go CLI (Go 1.26+) uses Cobra for commands, charmbracelet/huh for interactive CLI, charmbracelet/lipgloss for styled output. Cross-platform builds (linux/darwin/windows × amd64/arm64). GoReleaser for releases with cosign keyless signing of checksums.txt. SLSA L3 provenance attestations via actions/attest-build-provenance.

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: Applies to cli/** : CLI: Go 1.26+, dependencies in cli/go.mod (Cobra, charmbracelet/huh).

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-27T12:41:55.315Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T12:41:55.315Z
Learning: Applies to web/src/**/*.{tsx,ts} : Use Tailwind semantic classes (`text-foreground`, `bg-card`, `text-accent`, `text-success`, `bg-danger`) or CSS variables (`var(--so-*)`) for colors; never hardcode hex values

Applied to files:

  • web/src/pages/org/OrgChartSkeleton.stories.tsx
  • web/src/styles/global.css
  • web/src/pages/org/CeoNode.tsx
  • web/src/pages/org/AgentNode.tsx
📚 Learning: 2026-03-27T12:41:55.315Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T12:41:55.315Z
Learning: Applies to web/src/**/*.{tsx,ts} : Use token variables for shadows and borders (`var(--so-shadow-card-hover)`, `border-border`, `border-bright`)

Applied to files:

  • web/src/pages/org/OrgChartSkeleton.stories.tsx
  • web/src/styles/global.css
  • web/src/pages/org/CeoNode.tsx
  • web/src/pages/org/AgentNode.tsx
📚 Learning: 2026-03-27T12:41:55.315Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T12:41:55.315Z
Learning: Applies to web/src/**/*.{tsx,ts} : TypeScript 6.0: remove `baseUrl` (deprecated, will stop working in TS 7); `esModuleInterop` always true (cannot be set false); `types` defaults to `[]` (must explicitly list needed types); `DOM.Iterable` merged into `DOM`; `moduleResolution: 'classic'` and `'node10'` removed (use `'bundler'` or `'nodenext'`); `strict` defaults to true

Applied to files:

  • web/package.json
📚 Learning: 2026-03-27T12:41:55.315Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T12:41:55.315Z
Learning: Applies to web/src/**/*.{tsx,ts} : Use density-aware spacing tokens (`p-card`, `gap-section-gap`, `gap-grid-gap`) or standard Tailwind spacing; never hardcode pixel values for layout spacing

Applied to files:

  • web/src/pages/org/CeoNode.tsx
  • web/src/pages/org/AgentNode.tsx
  • web/src/pages/org/layout.ts
📚 Learning: 2026-03-19T07:13:44.964Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:13:44.964Z
Learning: Applies to src/synthorg/hr/**/*.py : HR package (hr/): hiring, firing, onboarding, offboarding, agent registry, performance tracking (task metrics, collaboration scoring, LLM calibration, collaboration overrides, trend detection), promotion/demotion (criteria evaluation, approval strategies, model mapping)

Applied to files:

  • web/src/pages/org/status-mapping.ts
📚 Learning: 2026-03-16T06:24:56.341Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-16T06:24:56.341Z
Learning: Applies to src/synthorg/hr/**/*.py : HR engine must provide: hiring, firing, onboarding, offboarding, agent registry, performance tracking (task metrics, collaboration scoring, trend detection), promotion/demotion

Applied to files:

  • web/src/pages/org/status-mapping.ts
🔇 Additional comments (47)
web/src/__tests__/App.test.tsx (1)

59-84: Per-test timeout addition is appropriate and scoped.

Using a test-level timeout (10_000) while keeping waitFor timeout at 5000 is a solid balance for lazy-loaded authenticated shell rendering under slower concurrent runs.

web/src/__tests__/pages/DashboardPage.test.tsx (3)

64-67: Static import + hoisted mock usage is correct.

This keeps module loading deterministic while preserving the mocked useDashboardData behavior.


80-83: Sync test conversion is consistent and clean.

Dropping unnecessary async flow improves readability without changing test intent.

Also applies to: 91-97, 99-103, 105-108, 110-113, 115-118, 120-124, 134-138, 140-144


85-89: Loading-state assertions now better match accessible UX.

Using getByLabelText/queryByLabelText('Loading dashboard') is a solid improvement for resilient, accessibility-aligned tests.

Also applies to: 126-132

web/src/pages/org/HierarchyEdge.tsx (1)

1-27: LGTM!

The component is well-structured with proper memoization. The use of var(--color-border-bright) CSS variable for stroke color correctly follows the design token guidelines.

web/src/pages/org/OrgChartSkeleton.tsx (1)

1-30: LGTM!

Good implementation with proper accessibility attributes (role="status", aria-live="polite", aria-label). The component correctly reuses SkeletonCard from the UI component library as per coding guidelines.

web/src/pages/org/OrgChartSkeleton.stories.tsx (1)

1-23: LGTM!

The story is well-configured with proper accessibility testing (a11y.test: 'error') and the previous review feedback about inline background styling has been addressed.

web/src/pages/org/status-mapping.ts (1)

1-30: LGTM!

Clean utility functions with proper documentation. The exhaustive switch in mapHrToRuntime handles all AgentStatus cases, and the consolidated fall-through for onboarding/active (from previous review feedback) improves readability.

web/src/__tests__/utils/errors.property.test.ts (1)

1-49: LGTM!

Good approach to avoid the async leak issue from Axios's fetch adapter. The mock properly exposes isAxiosError both as a default export property and named export. The property-based tests effectively verify security (no body leakage) and robustness (non-empty messages).

web/src/__tests__/pages/org/status-mapping.test.ts (1)

1-43: LGTM!

Comprehensive test coverage for both functions. The edge case test at lines 39-42 properly documents the scenario where runtime override takes precedence over stale HR status, which is important for understanding the intended behavior.

web/src/pages/org/NodeContextMenu.tsx (1)

113-139: LGTM!

The component correctly handles all three node types with appropriate menu items. Previous review feedback has been addressed (explicit type="button", separate ceoItems). Good use of semantic Tailwind classes and ARIA roles.

web/src/pages/org/NodeContextMenu.stories.tsx (1)

1-48: LGTM!

All three nodeType variants are now covered with stories, and accessibility testing is properly configured. Previous review feedback has been fully addressed.

web/src/__tests__/pages/org/NodeContextMenu.test.tsx (1)

88-106: Property-based invariants are well covered.

The fc.assert(fc.property(...)) block meaningfully validates menu structure across supported nodeType values and complements deterministic tests.

web/src/styles/global.css (1)

7-7: React Flow base stylesheet import is correctly wired.

This ensures XYFlow primitives render with expected baseline behavior/styles.

web/package.json (1)

18-18: Dependency additions align with the new graph-layout surface.

The added runtime/layout package and typings are consistent with the org-chart dagre integration.

Also applies to: 55-55

web/src/__tests__/pages/org/OrgChartSkeleton.test.tsx (1)

6-19: Good accessibility coverage for loading semantics.

These assertions lock in expected ARIA behavior for the skeleton state.

CLAUDE.md (1)

127-127: Documentation updates are consistent with the implemented org-chart architecture.

The hook/store and dependency notes now reflect the new page composition and layout stack.

Also applies to: 131-131, 323-323

web/src/__tests__/pages/org/DepartmentStatsBar.test.tsx (1)

17-26: Cost rendering branch coverage is solid.

Both present and null cost paths are tested, which protects the conditional UI behavior.

web/src/pages/org/AgentNode.tsx (1)

35-35: No action required. The important modifier syntax using suffix form (bg-border-bright!, size-1.5!) is correct for Tailwind CSS v4 and matches the official specification. This is the preferred syntax in v4; the prefix form (!bg-red-500) is a v3 pattern that is deprecated.

web/src/__tests__/pages/org/OrgChartToolbar.test.tsx (1)

1-52: LGTM! Clean test structure with proper mock isolation.

The createProps() factory pattern correctly addresses the previous review feedback about shared mock instances. Tests cover the essential rendering and interaction behaviors.

Consider adding a test for clicking "Hierarchy" when viewMode is 'force' to verify the toggle works in both directions.

web/src/__tests__/pages/org/layout.test.ts (1)

1-104: LGTM! Comprehensive layout test coverage.

The test suite thoroughly covers applyDagreLayout behavior including edge cases (empty input, missing node references, department grouping). The past review comment about the misleading test description has been addressed.

web/src/pages/org/DepartmentStatsBar.tsx (1)

1-30: LGTM! Clean implementation following component reuse guidelines.

The component properly reuses StatPill from the UI library, uses semantic Tailwind classes, and correctly defaults currency to 'USD' to match the costUsd prop semantics (addressing the previous review feedback).

web/src/pages/org/CeoNode.tsx (1)

1-52: LGTM! Well-structured node component with proper UI reuse.

The component correctly reuses Avatar and StatusBadge from the UI library, uses semantic Tailwind classes throughout, includes proper accessibility attributes (aria-label, data-testid), and applies Tailwind v4 postfix important syntax on Handle elements (addressing the previous review).

web/src/__tests__/stores/agents.test.ts (1)

1-82: LGTM! Thorough store test coverage.

The test suite comprehensively covers useAgentsStore behavior including edge cases for WebSocket event handling (missing fields, invalid status values, wrong event types). Proper state isolation via beforeEach reset.

web/src/pages/org/DepartmentStatsBar.stories.tsx (1)

1-48: LGTM! Good story coverage for component states.

The stories cover the key variants: default with cost, null cost (testing conditional rendering), and zero values. The decorator constrains width appropriately for visual testing.

web/src/stores/agents.ts (1)

1-39: LGTM! Well-designed store with defensive payload validation.

The store implementation is clean and defensive:

  • VALID_RUNTIME_STATUSES set ensures only known status values are accepted
  • Type guards properly validate payload fields before processing
  • Immutable state updates via spread operator
web/src/__tests__/pages/org/OrgChartPage.test.tsx (1)

1-143: LGTM!

The test suite provides good coverage of the OrgChartPage UI states including loading, empty, error, WebSocket warnings, and the presence of React Flow canvas and toolbar. The mock pattern with module-scoped variables and beforeEach reset is appropriate for controlling useOrgChartData return values across tests.

web/src/pages/org/DepartmentGroupNode.tsx (2)

1-51: LGTM!

The component follows coding guidelines well: uses semantic Tailwind classes (text-foreground, bg-card/50, border-border), design token-based health colors, font-sans/font-mono for typography, and properly reuses the DepartmentStatsBar component. The memoization and accessibility attributes are appropriate.


35-36: The text-micro class is properly defined in your design system (--so-text-micro: 10px in web/src/styles/design-tokens.css) and is already used consistently across multiple components. No action needed.

web/src/pages/org/DepartmentGroupNode.stories.tsx (1)

1-87: LGTM!

The stories follow Storybook 10 patterns with proper parameters.a11y.test: 'error' configuration. Good coverage of health states (Healthy/Warning/Critical) and the costUsd: null edge case in the Critical story.

web/src/pages/org/OrgChartToolbar.tsx (1)

1-88: LGTM!

The toolbar component is well-implemented with proper accessibility: aria-pressed on toggle buttons, aria-label on icon-only buttons, and aria-hidden on decorative icons. Uses semantic Tailwind classes and reuses the Button component from @/components/ui/.

web/src/pages/org/CeoNode.stories.tsx (1)

1-100: LGTM!

The stories provide complete coverage of all four AgentRuntimeStatus values (Active, Idle, Error, Offline) with proper Storybook 10 configuration including parameters.a11y.test: 'error'.

web/src/__tests__/stores/company.test.ts (1)

1-135: LGTM!

Solid test coverage for useCompanyStore including success/failure paths for data fetching, partial failure handling in fetchDepartmentHealths, and WebSocket event handling. The use of vi.waitFor for async assertions and proper mock/state isolation in beforeEach are good patterns.

web/src/hooks/useOrgChartData.ts (2)

1-85: Overall hook structure is sound.

The hook properly sequences data fetching (config before department health), sets up polling and WebSocket bindings, and memoizes derived graph data. The pattern of accessing stores via .getState() in handlers avoids stale closure issues.


46-50: No action required — the ESLint rule is valid.

The @eslint-react/exhaustive-deps rule exists and is actively used throughout the codebase (at least 7 instances). The project uses @eslint-react/eslint-plugin v3, which provides this rule as part of its hooks analysis. The disable comment is correct and has the intended effect.

web/src/pages/OrgChartPage.tsx (2)

1-310: Well-structured page implementation.

The page correctly addresses all previous review feedback: defensive getAgentName guard, early return for unimplemented force view mode, and Button asChild composition. Good use of semantic Tailwind classes, existing UI components (ErrorBoundary, EmptyState, ConfirmDialog, Button), and proper accessibility patterns. The viewport persistence logic is robust with validation.


262-262: No action needed. React Flow's hideAttribution option does not require a paid Pro license and is freely available under the MIT license. The attribution can be removed without any license restrictions.

web/src/__tests__/pages/org/build-org-tree.test.ts (3)

288-298: Redundant company_name mutation before function call.

Line 293 mutates config.company_name, but makeConfig already sets company_name: 'Test Corp'. The mutation is sufficient on its own. This was flagged in a past review.

♻️ Cleaner alternative
   it('includes companyName in CEO node data', () => {
     const agents = [
       makeAgent({ id: 'ceo', name: 'Boss', department: 'executive', level: 'c_suite' }),
     ]
-    const config = makeConfig(agents)
-    config.company_name = 'Acme Inc'
+    const config = { ...makeConfig(agents), company_name: 'Acme Inc' }
     const result = buildOrgTree(config, {}, [])

     const ceoNode = result.nodes.find((n) => n.type === 'ceo')
     expect(ceoNode!.data.companyName).toBe('Acme Inc')
   })

1-313: LGTM - Comprehensive test coverage for org tree building.

The test suite thoroughly covers CEO selection rules, department grouping, edge generation, terminated agent filtering, health data enrichment, runtime status overrides, and edge cases like empty departments. The factory helpers (makeAgent, makeConfig, makeHealth) provide a clean DSL for constructing test fixtures.


184-187: 🧹 Nitpick | 🔵 Trivial

Non-null assertion on array index access.

Line 186 uses agentNodes[0]! which assumes the filtered array is non-empty. While the test setup guarantees one active agent, using .at(0) with an explicit check or expect(agentNodes[0]).toBeDefined() first would be more defensive.

💡 Safer alternative
     const agentNodes = result.nodes.filter((n) => n.type === 'agent' || n.type === 'ceo')
     expect(agentNodes).toHaveLength(1)
-    expect(agentNodes[0]!.data.name).toBe('Active')
+    expect(agentNodes[0]?.data.name).toBe('Active')
			> Likely an incorrect or invalid review comment.
web/src/stores/company.ts (1)

32-47: LGTM!

The fetchDepartmentHealths implementation correctly iterates over config.departments rather than paginating through an API list, addressing the earlier review feedback. The parallel fetching with individual error handling (catching per-department failures and filtering nulls) is a good resilience pattern.

web/src/pages/org/build-org-tree.ts (3)

8-32: Index signatures on node data interfaces are appropriate for React Flow compatibility.

The [key: string]: unknown index signatures on AgentNodeData, CeoNodeData, and DepartmentGroupData allow these types to satisfy React Flow's Node<T> constraint where T extends Record<string, unknown>. This is the correct pattern for React Flow v12.


68-196: LGTM - Well-structured tree-building logic.

The buildOrgTree function follows a clear progression: filter terminated agents → group by department → identify CEO → build department nodes with health data → create agent nodes and hierarchy edges → connect CEO to department heads. The deduplication check for CEO-to-head edges (lines 181-191) correctly prevents duplicate edges when team structure already establishes the connection.


200-231: LGTM - Helper functions are well-documented.

The tiebreaker behavior ("first wins" by array order) is now documented in comments above findHighestSeniority and findCeo, addressing the earlier review feedback. The findDepartmentHead function correctly excludes the CEO from candidates and avoids unnecessary array spread.

web/src/pages/org/layout.ts (3)

98-158: LGTM - Clean separation of pure computation and side effects.

The refactored two-step approach (Step 1: compute group bounds purely in groupResults.map(), Step 2: adjust children in a separate loop) addresses the earlier review feedback about mixing concerns. The code is now easier to reason about.


1-161: Well-implemented dagre layout utility.

The implementation correctly:

  • Separates group nodes from leaf nodes for dagre processing
  • Increases spacing to account for department chrome (padding + header)
  • Handles the no-leaf-nodes case with a direction-aware grid
  • Converts dagre center coordinates to React Flow top-left positions
  • Computes group bounds from children and adjusts child positions to be group-relative
  • Preserves existing style properties when setting dimensions

100-115: Empty group positioning logic may place nodes off-canvas for LR direction.

When direction === 'LR' and there are populated groups, empty groups are positioned at x = minor * 240 (starting from 0) and y = contentMaxY + padding + major * 160. However, if contentMaxY is small, this could place empty groups far below the main content. The TB direction uses contentMaxX + padding for the X offset, but LR doesn't use contentMaxX at all for X positioning, which may cause empty groups to overlap with populated content horizontally.

unmount()
}),
{ numRuns: 20 },
{ numRuns: 10 },
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Keep stronger property-test coverage or make run count environment-aware.

Line 54 reduces numRuns from 20 to 10, which weakens randomized coverage and lowers confidence in this invariant test. Consider keeping 20 in CI and using a lower value only for local runs.

Suggested adjustment
-      { numRuns: 10 },
+      { numRuns: process.env.CI ? 20 : 10 },
📝 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.

Suggested change
{ numRuns: 10 },
{ numRuns: process.env.CI ? 20 : 10 },
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/__tests__/pages/dashboard/ActivityFeed.test.tsx` at line 54, The test
lowered the randomized iteration count by changing the numRuns value in
ActivityFeed.test.tsx, which weakens coverage; restore stronger coverage by
making numRuns environment-aware (e.g., use process.env.CI or a TEST_RUNS env
var) so CI uses 20 while local runs can default to 10, and update the numRuns
reference in the test (the variable used in the ActivityFeed test block) to read
from that env-aware value.

function Wrapper({ data }: { data: AgentNodeData }) {
return (
<ReactFlowProvider>
<div style={{ width: 400, height: 200 }}>
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Replace hardcoded inline dimensions with Tailwind sizing classes.

Line 11 hardcodes pixel dimensions in inline styles. Prefer standard Tailwind sizing utilities for consistency with layout token rules.

♻️ Proposed fix
-      <div style={{ width: 400, height: 200 }}>
+      <div className="h-52 w-full max-w-md">

As per coding guidelines: Spacing: use density-aware tokens (...) or standard Tailwind spacing. NEVER hardcode pixel values for layout spacing.

📝 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.

Suggested change
<div style={{ width: 400, height: 200 }}>
<div className="h-52 w-full max-w-md">
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/pages/org/AgentNode.stories.tsx` at line 11, The story contains a div
with hardcoded inline style width/height in AgentNode.stories.tsx; replace that
inline style on the container div with the appropriate Tailwind sizing utility
classes (use the nearest standard Tailwind classes or your design system tokens,
e.g., w-*/h-* equivalents) so the component uses density-aware/tailwind sizing
rather than pixel values; update the JSX div (the container around the story
preview) to use className with Tailwind sizing utilities instead of style={{
width: 400, height: 200 }}.

Comment on lines +60 to +65
for (const node of leafNodes) {
g.setNode(node.id, {
width: node.measured?.width ?? DEFAULT_NODE_WIDTH,
height: node.measured?.height ?? DEFAULT_NODE_HEIGHT,
})
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Layout computed with placeholder sizes before React Flow measures nodes.

The dagre layout uses node.measured?.width with DEFAULT_NODE_WIDTH (160) and DEFAULT_NODE_HEIGHT (80) as fallbacks. On initial render, measured is undefined, so all nodes get uniform placeholder sizes. This was noted in past reviews and marked as addressed, but the fundamental issue remains: the initial layout may not match rendered node sizes.

The current approach is pragmatic for an MVP—nodes will be reasonably positioned, and React Flow's built-in pan/zoom allows users to adjust. For production, consider re-running layout after nodes are measured or using fixed dimensions in node components.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/pages/org/layout.ts` around lines 60 - 65, The dagre layout currently
uses placeholder sizes (DEFAULT_NODE_WIDTH/DEFAULT_NODE_HEIGHT) when
node.measured is undefined, yielding an initial layout that mismatches rendered
nodes; update the flow so that after React Flow measures nodes (i.e., when
measured.width/height become available on leafNodes) you recompute the layout
and call g.setNode with the real measured dimensions and re-run the dagre layout
pass (or alternatively enforce fixed dimensions inside the node component),
ensuring you trigger the layout update from the same routine that uses leafNodes
and g.setNode so nodes are laid out with actual sizes instead of placeholders.

maxZoom={2}
proOptions={{ hideAttribution: true }}
>
<Background color="var(--color-border)" gap={24} size={1} />
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for --color-border CSS variable definition
rg -n "\-\-color-border" --type=css web/
rg -n "\-\-color-border" web/src/index.css web/src/globals.css 2>/dev/null || echo "No globals.css found"

Repository: Aureliolo/synthorg

Length of output: 223


🏁 Script executed:

# Check what --border resolves to and explore the full token structure
rg -n "^\s*--border:" web/src/styles/ -A 1
rg -n "^\s*--so-border" web/src/styles/ -A 1
cat web/src/styles/global.css | head -100

Repository: Aureliolo/synthorg

Length of output: 4144


🏁 Script executed:

# Check how Background component is used elsewhere and what color patterns are recommended
rg -n "Background color=" web/src/ --type=tsx --type=ts
rg -n "var(--so-" web/src/styles/ | head -20

Repository: Aureliolo/synthorg

Length of output: 153


Use the recommended var(--so-border) token variable instead of the intermediate --color-border variable.

The CSS variable --color-border is defined and functional (--color-border--border--so-border#1e1e2e). However, per the design token pattern, use var(--so-border) directly for consistency with the SynthOrg theme bridge layer, rather than routing through the shadcn intermediate variable.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/pages/OrgChartPage.tsx` at line 264, Replace the intermediate CSS
token with the canonical SynthOrg token: in the Background component usage
(Background color="var(--color-border)" gap={24} size={1}), change the color
prop to use var(--so-border) instead of var(--color-border) so the component
uses the recommended design token directly.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 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/pages/org/NodeContextMenu.tsx`:
- Line 117: The NodeContextMenu is positioning the menu at raw client
coordinates (style={{ top: position.y, left: position.x }}) which can overflow
the viewport; add viewport boundary checking by computing a boundedPosition
(e.g., in a useMemo inside NodeContextMenu) that clamps x to
Math.min(position.x, window.innerWidth - menuWidth - margin) and y to
Math.min(position.y, window.innerHeight - menuHeight - margin) using the menu's
expected width/height (use items.length to estimate height) and then use that
boundedPosition for the inline style instead of position.
- Around line 113-120: The context menu returned by the NodeContextMenu
component (the element using menuRef with role="menu" and
data-testid="node-context-menu") is missing an aria-label for screen readers;
update that root div to include a descriptive aria-label (e.g., "Node context
menu" or a localized/prop-driven label) so assistive technology can announce the
menu purpose when role="menu" is used.

In `@web/src/pages/org/OrgChartToolbar.stories.tsx`:
- Around line 5-16: The story wrapper currently hardcodes state and callbacks by
rendering InteractiveToolbar directly, causing Default.args to be ignored;
change the custom render to accept story args and pass them into
InteractiveToolbar (and make InteractiveToolbar accept props from args) so
viewMode, onViewModeChange, onFitView, onZoomIn, and onZoomOut come from args
(falling back to internal state/noop when not provided), and ensure Default.args
is defined and used to initialize the component props so Controls and Docs
reflect the story args for OrgChartToolbar.

In `@web/src/stores/company.ts`:
- Around line 32-47: The fetchDepartmentHealths success path currently updates
departmentHealths but never clears a prior error, so restore/clear error state
when health refresh succeeds: in fetchDepartmentHealths (the async function)
ensure that after computing departmentHealths you call set with both
departmentHealths and error cleared (e.g., set({ departmentHealths, error:
undefined }) or similar), or alternatively clear the error at the start of the
try block before awaiting results; reference fetchDepartmentHealths, set and
getCompanyStore.getState().config when making the change.
- Around line 49-55: The WS event handler updateFromWsEvent currently refetches
company config via useCompanyStore.getState().fetchCompanyData() on
agent.hired/agent.fired but does not refresh department health, leaving
departmentHealths stale; after the fetchCompanyData() call (inside the same
branch) invoke the store method that reloads department health (e.g.,
useCompanyStore.getState().fetchDepartmentHealths()) or, if that method doesn't
exist, add a fetchDepartmentHealths() method to the company store and call it
here so departmentHealths is updated immediately (preserve the existing .catch
handling).
🪄 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: 86561300-911e-4967-9dd2-9f9cac7a5828

📥 Commits

Reviewing files that changed from the base of the PR and between 551b32b and 683d4e9.

📒 Files selected for processing (3)
  • web/src/pages/org/NodeContextMenu.tsx
  • web/src/pages/org/OrgChartToolbar.stories.tsx
  • web/src/stores/company.ts
📜 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 Sandbox
  • GitHub Check: Build Web
  • GitHub Check: Build Backend
  • GitHub Check: Dashboard Test
  • GitHub Check: Dependency Review
  • GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (2)
web/src/**/*.{tsx,ts}

📄 CodeRabbit inference engine (CLAUDE.md)

web/src/**/*.{tsx,ts}: Always reuse existing components from web/src/components/ui/ before creating new ones. Check the required component inventory (StatusBadge, MetricCard, Sparkline, SectionCard, AgentCard, DeptHealthBar, ProgressGauge, StatPill, Avatar, Button, Toast, Skeleton, EmptyState, ErrorBoundary, ConfirmDialog, CommandPalette, InlineEdit, AnimatedPresence, StaggerGroup, TaskStatusIndicator, PriorityBadge)
Use Tailwind semantic classes (text-foreground, bg-card, text-accent, text-success, bg-danger) or CSS variables (var(--so-*)) for colors; never hardcode hex values
Use font-sans or font-mono for typography (maps to Geist tokens); never set fontFamily directly
Use density-aware spacing tokens (p-card, gap-section-gap, gap-grid-gap) or standard Tailwind spacing; never hardcode pixel values for layout spacing
Use token variables for shadows and borders (var(--so-shadow-card-hover), border-border, border-bright)
Do NOT recreate status dots inline -- use <StatusBadge>; do NOT build card-with-header layouts from scratch -- use <SectionCard>; do NOT create metric displays inline -- use <MetricCard>; do NOT render initials circles manually -- use <Avatar>; do NOT create complex (>8 line) JSX inside .map() -- extract to shared component
TypeScript 6.0: remove baseUrl (deprecated, will stop working in TS 7); esModuleInterop always true (cannot be set false); types defaults to [] (must explicitly list needed types); DOM.Iterable merged into DOM; moduleResolution: 'classic' and 'node10' removed (use 'bundler' or 'nodenext'); strict defaults to true
Storybook 10 is ESM-only; @storybook/addon-essentials, @storybook/addon-interactions, @storybook/test, @storybook/blocks no longer published (features built into core storybook); @storybook/addon-docs must be installed separately if using tags: ['autodocs']

Files:

  • web/src/pages/org/OrgChartToolbar.stories.tsx
  • web/src/pages/org/NodeContextMenu.tsx
  • web/src/stores/company.ts
web/src/**/*.stories.tsx

📄 CodeRabbit inference engine (CLAUDE.md)

Storybook 10: use definePreview from @storybook/react-vite for type-safe config; import from storybook/test (not @storybook/test) and storybook/actions (not @storybook/addon-actions); use parameters.backgrounds.options (object keyed by name) + initialGlobals.backgrounds.value; use parameters.a11y.test: 'error' | 'todo' | 'off' for accessibility testing

Files:

  • web/src/pages/org/OrgChartToolbar.stories.tsx
🧠 Learnings (6)
📓 Common learnings
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/).
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).
📚 Learning: 2026-03-27T12:41:55.315Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T12:41:55.315Z
Learning: Applies to web/src/**/*.{tsx,ts} : Storybook 10 is ESM-only; storybook/addon-essentials, storybook/addon-interactions, storybook/test, storybook/blocks no longer published (features built into core `storybook`); storybook/addon-docs must be installed separately if using `tags: ['autodocs']`

Applied to files:

  • web/src/pages/org/OrgChartToolbar.stories.tsx
📚 Learning: 2026-03-27T12:41:55.315Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T12:41:55.315Z
Learning: Applies to web/src/**/*.stories.tsx : Storybook 10: use `definePreview` from `storybook/react-vite` for type-safe config; import from `storybook/test` (not `storybook/test`) and `storybook/actions` (not `storybook/addon-actions`); use `parameters.backgrounds.options` (object keyed by name) + `initialGlobals.backgrounds.value`; use `parameters.a11y.test: 'error' | 'todo' | 'off'` for accessibility testing

Applied to files:

  • web/src/pages/org/OrgChartToolbar.stories.tsx
📚 Learning: 2026-03-27T12:41:55.315Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T12:41:55.315Z
Learning: Applies to web/src/components/ui/*.{tsx,ts} : When creating new shared UI components, place in `web/src/components/ui/` with kebab-case filename, create adjacent `.stories.tsx` with all states, export props as TypeScript interface, use design tokens exclusively (no hardcoded colors/fonts/spacing), import `cn` from `@/lib/utils` for conditional class merging

Applied to files:

  • web/src/pages/org/OrgChartToolbar.stories.tsx
📚 Learning: 2026-03-27T12:41:55.315Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T12:41:55.315Z
Learning: Applies to web/src/**/*.{tsx,ts} : Do NOT recreate status dots inline -- use `<StatusBadge>`; do NOT build card-with-header layouts from scratch -- use `<SectionCard>`; do NOT create metric displays inline -- use `<MetricCard>`; do NOT render initials circles manually -- use `<Avatar>`; do NOT create complex (>8 line) JSX inside `.map()` -- extract to shared component

Applied to files:

  • web/src/pages/org/OrgChartToolbar.stories.tsx
📚 Learning: 2026-03-27T12:41:55.315Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T12:41:55.315Z
Learning: Applies to web/src/**/*.{tsx,ts} : Always reuse existing components from `web/src/components/ui/` before creating new ones. Check the required component inventory (StatusBadge, MetricCard, Sparkline, SectionCard, AgentCard, DeptHealthBar, ProgressGauge, StatPill, Avatar, Button, Toast, Skeleton, EmptyState, ErrorBoundary, ConfirmDialog, CommandPalette, InlineEdit, AnimatedPresence, StaggerGroup, TaskStatusIndicator, PriorityBadge)

Applied to files:

  • web/src/pages/org/OrgChartToolbar.stories.tsx
🔇 Additional comments (5)
web/src/pages/org/OrgChartToolbar.stories.tsx (1)

18-24: Meta configuration looks correct for autodocs and accessibility.

Good call setting component: OrgChartToolbar and enabling a11y.test: 'error'.

As per coding guidelines: “use parameters.a11y.test: 'error' | 'todo' | 'off' for accessibility testing.”

web/src/pages/org/NodeContextMenu.tsx (4)

1-4: Imports are appropriate and minimal.

Standard React 19 hooks, lucide-react icons for menu visuals, utility function, and toast store for stub action feedback. No issues.


45-61: Event listener setup and cleanup is correct.

The outside-click detection using mousedown and Escape key handling are properly registered and cleaned up on unmount. The as Node cast (previously flagged) is correctly applied.


99-111: Node type handling is correctly implemented.

The dedicated ceoItems array (previously flagged) now properly limits CEO nodes to "View Details" only, preventing exposure of agent CRUD actions. The selection logic correctly routes all three node types.


121-136: Menu item rendering follows design system conventions.

The buttons correctly include type="button" (previously flagged), use semantic Tailwind classes (text-foreground, text-danger, hover:bg-card-hover), and proper ARIA attributes. Icon sizing with size-3.5 and aria-hidden="true" is appropriate.

Comment on lines +5 to +16
function InteractiveToolbar() {
const [viewMode, setViewMode] = useState<ViewMode>('hierarchy')
return (
<OrgChartToolbar
viewMode={viewMode}
onViewModeChange={setViewMode}
onFitView={() => {}}
onZoomIn={() => {}}
onZoomOut={() => {}}
/>
)
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Wire story args through the custom render wrapper.

Default.args (Line [31]-Line [38]) are currently ignored because Line [25] renders InteractiveToolbar without args, and the wrapper hardcodes callbacks/state. This weakens Controls/Docs fidelity.

♻️ Proposed refactor
 import { useState } from 'react'
 import type { Meta, StoryObj } from '@storybook/react'
 import { OrgChartToolbar, type ViewMode } from './OrgChartToolbar'
 
-function InteractiveToolbar() {
-  const [viewMode, setViewMode] = useState<ViewMode>('hierarchy')
+type ToolbarProps = React.ComponentProps<typeof OrgChartToolbar>
+
+function InteractiveToolbar(args: ToolbarProps) {
+  const [viewMode, setViewMode] = useState<ViewMode>(args.viewMode)
   return (
     <OrgChartToolbar
+      {...args}
       viewMode={viewMode}
-      onViewModeChange={setViewMode}
-      onFitView={() => {}}
-      onZoomIn={() => {}}
-      onZoomOut={() => {}}
+      onViewModeChange={(mode) => {
+        setViewMode(mode)
+        args.onViewModeChange(mode)
+      }}
     />
   )
 }
@@
-  render: () => <InteractiveToolbar />,
+  render: (args) => <InteractiveToolbar {...args} />,
 } satisfies Meta<typeof OrgChartToolbar>

Also applies to: 25-25, 31-38

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/pages/org/OrgChartToolbar.stories.tsx` around lines 5 - 16, The story
wrapper currently hardcodes state and callbacks by rendering InteractiveToolbar
directly, causing Default.args to be ignored; change the custom render to accept
story args and pass them into InteractiveToolbar (and make InteractiveToolbar
accept props from args) so viewMode, onViewModeChange, onFitView, onZoomIn, and
onZoomOut come from args (falling back to internal state/noop when not
provided), and ensure Default.args is defined and used to initialize the
component props so Controls and Docs reflect the story args for OrgChartToolbar.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (1)
web/src/stores/company.ts (1)

32-45: ⚠️ Potential issue | 🟡 Minor

Clear stale error after successful department health refresh.

Line 43 updates departmentHealths but leaves any previous error intact, so recovered polls can still render an error state.

Suggested fix
   fetchDepartmentHealths: async () => {
     try {
       const config = useCompanyStore.getState().config
       if (!config) return
       const healthPromises = config.departments.map((dept) =>
         getDepartmentHealth(dept.name).catch(() => null),
       )
       const healthResults = await Promise.all(healthPromises)
       const departmentHealths = healthResults.filter(
         (h): h is DepartmentHealth => h !== null,
       )
-      set({ departmentHealths })
+      set({ departmentHealths, error: null })
     } catch (err) {
       set({ error: getErrorMessage(err) })
     }
   },
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/stores/company.ts` around lines 32 - 45, In fetchDepartmentHealths,
after successfully computing departmentHealths call set to also clear any
previous error (e.g., set({ departmentHealths, error: null })) so a recovered
poll doesn't leave an old error visible; ensure the change is applied in the
fetchDepartmentHealths function where set is currently called to update
departmentHealths.
🤖 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/pages/org/NodeContextMenu.tsx`:
- Line 124: The menuLabel currently uses nodeType === 'department' ? 'Department
actions' : 'Agent actions' and thus labels CEO nodes as "Agent actions"; update
the logic in NodeContextMenu to distinguish 'ceo' explicitly (e.g., nodeType ===
'department' ? 'Department actions' : nodeType === 'ceo' ? 'CEO actions' :
'Agent actions') so CEO nodes get a specific "CEO actions" label and keep
existing behavior for 'agent' and 'department'.
- Around line 119-122: The bounding logic for the context menu only prevents
right/bottom overflow; update the useMemo that computes boundedPosition to clamp
both minimum and maximum bounds (e.g., use Math.max(position.x, margin) and
Math.max(position.y, margin) before Math.min with window.innerWidth - menuWidth
- margin and window.innerHeight - menuHeight - margin) so the menu can't render
off the left/top edges; also include menuWidth, menuHeight, and margin in the
useMemo dependency array so recalculation happens when those change.

---

Duplicate comments:
In `@web/src/stores/company.ts`:
- Around line 32-45: In fetchDepartmentHealths, after successfully computing
departmentHealths call set to also clear any previous error (e.g., set({
departmentHealths, error: null })) so a recovered poll doesn't leave an old
error visible; ensure the change is applied in the fetchDepartmentHealths
function where set is currently called to update departmentHealths.
🪄 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: 0bcfd08f-4de3-4c0d-a6ea-631934beb658

📥 Commits

Reviewing files that changed from the base of the PR and between 683d4e9 and 6bca9ee.

📒 Files selected for processing (2)
  • web/src/pages/org/NodeContextMenu.tsx
  • web/src/stores/company.ts
📜 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: Dashboard Test
  • GitHub Check: Build Web
  • GitHub Check: Build Backend
  • GitHub Check: Dependency Review
  • GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (1)
web/src/**/*.{tsx,ts}

📄 CodeRabbit inference engine (CLAUDE.md)

web/src/**/*.{tsx,ts}: Always reuse existing components from web/src/components/ui/ before creating new ones. Check the required component inventory (StatusBadge, MetricCard, Sparkline, SectionCard, AgentCard, DeptHealthBar, ProgressGauge, StatPill, Avatar, Button, Toast, Skeleton, EmptyState, ErrorBoundary, ConfirmDialog, CommandPalette, InlineEdit, AnimatedPresence, StaggerGroup, TaskStatusIndicator, PriorityBadge)
Use Tailwind semantic classes (text-foreground, bg-card, text-accent, text-success, bg-danger) or CSS variables (var(--so-*)) for colors; never hardcode hex values
Use font-sans or font-mono for typography (maps to Geist tokens); never set fontFamily directly
Use density-aware spacing tokens (p-card, gap-section-gap, gap-grid-gap) or standard Tailwind spacing; never hardcode pixel values for layout spacing
Use token variables for shadows and borders (var(--so-shadow-card-hover), border-border, border-bright)
Do NOT recreate status dots inline -- use <StatusBadge>; do NOT build card-with-header layouts from scratch -- use <SectionCard>; do NOT create metric displays inline -- use <MetricCard>; do NOT render initials circles manually -- use <Avatar>; do NOT create complex (>8 line) JSX inside .map() -- extract to shared component
TypeScript 6.0: remove baseUrl (deprecated, will stop working in TS 7); esModuleInterop always true (cannot be set false); types defaults to [] (must explicitly list needed types); DOM.Iterable merged into DOM; moduleResolution: 'classic' and 'node10' removed (use 'bundler' or 'nodenext'); strict defaults to true
Storybook 10 is ESM-only; @storybook/addon-essentials, @storybook/addon-interactions, @storybook/test, @storybook/blocks no longer published (features built into core storybook); @storybook/addon-docs must be installed separately if using tags: ['autodocs']

Files:

  • web/src/pages/org/NodeContextMenu.tsx
  • web/src/stores/company.ts
🧠 Learnings (1)
📓 Common learnings
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/).
🔇 Additional comments (3)
web/src/stores/company.ts (2)

22-30: fetchCompanyData state transitions are clean and deterministic.

Good handling of loading/error across both success and failure paths.


49-59: WS lifecycle refresh flow looks correct.

Chaining fetchCompanyData() then fetchDepartmentHealths() for agent.hired/agent.fired keeps org structure and health aligned.

web/src/pages/org/NodeContextMenu.tsx (1)

1-153: Well-structured context menu implementation.

The component correctly:

  • Separates menu items by node type with appropriate actions for each
  • Handles outside click and Escape dismissal with proper cleanup
  • Uses semantic Tailwind classes (border-border, bg-card, text-foreground, text-danger)
  • Includes accessibility attributes (role="menu", role="menuitem", aria-label, aria-hidden)
  • Clamps position to viewport bounds to prevent overflow
  • Uses type="button" to prevent form submission issues

The stubbed actions with toast feedback provide clear user communication while backend APIs are pending.

@Aureliolo
Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 27, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@Aureliolo
Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 27, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 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/stores/company.ts`:
- Around line 36-43: The code currently converts per-department failures to null
(via healthPromises) so Promise.all never rejects and then always calls set({
departmentHealths, error: null }), which clears any real outage state; change
the logic after awaiting healthResults to detect the "all failed" case (e.g.,
departmentHealths.length === 0 && config.departments.length > 0) and in that
case set an error (or preserve the previous error) instead of clearing it;
otherwise (at least one success) set departmentHealths and clear error as now —
update the block that builds healthPromises/healthResults and the set(...) call
(referencing getDepartmentHealth, departmentHealths, healthPromises,
healthResults, and set) to implement this conditional error handling.
🪄 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: 3d5598db-fc8e-48d1-964d-322f753a386e

📥 Commits

Reviewing files that changed from the base of the PR and between 6bca9ee and 4203a61.

📒 Files selected for processing (2)
  • web/src/pages/org/NodeContextMenu.tsx
  • web/src/stores/company.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (1)
web/src/**/*.{tsx,ts}

📄 CodeRabbit inference engine (CLAUDE.md)

web/src/**/*.{tsx,ts}: Always reuse existing components from web/src/components/ui/ before creating new ones. Check the required component inventory (StatusBadge, MetricCard, Sparkline, SectionCard, AgentCard, DeptHealthBar, ProgressGauge, StatPill, Avatar, Button, Toast, Skeleton, EmptyState, ErrorBoundary, ConfirmDialog, CommandPalette, InlineEdit, AnimatedPresence, StaggerGroup, TaskStatusIndicator, PriorityBadge)
Use Tailwind semantic classes (text-foreground, bg-card, text-accent, text-success, bg-danger) or CSS variables (var(--so-*)) for colors; never hardcode hex values
Use font-sans or font-mono for typography (maps to Geist tokens); never set fontFamily directly
Use density-aware spacing tokens (p-card, gap-section-gap, gap-grid-gap) or standard Tailwind spacing; never hardcode pixel values for layout spacing
Use token variables for shadows and borders (var(--so-shadow-card-hover), border-border, border-bright)
Do NOT recreate status dots inline -- use <StatusBadge>; do NOT build card-with-header layouts from scratch -- use <SectionCard>; do NOT create metric displays inline -- use <MetricCard>; do NOT render initials circles manually -- use <Avatar>; do NOT create complex (>8 line) JSX inside .map() -- extract to shared component
TypeScript 6.0: remove baseUrl (deprecated, will stop working in TS 7); esModuleInterop always true (cannot be set false); types defaults to [] (must explicitly list needed types); DOM.Iterable merged into DOM; moduleResolution: 'classic' and 'node10' removed (use 'bundler' or 'nodenext'); strict defaults to true
Storybook 10 is ESM-only; @storybook/addon-essentials, @storybook/addon-interactions, @storybook/test, @storybook/blocks no longer published (features built into core storybook); @storybook/addon-docs must be installed separately if using tags: ['autodocs']

Files:

  • web/src/pages/org/NodeContextMenu.tsx
  • web/src/stores/company.ts
🧠 Learnings (1)
📓 Common learnings
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/).
🔇 Additional comments (1)
web/src/pages/org/NodeContextMenu.tsx (1)

1-154: Clean implementation with all prior feedback addressed.

The component is well-structured with:

  • Proper separation of menu item definitions per node type (agent, ceo, department)
  • Correct viewport boundary clamping using Math.max/Math.min for all edges
  • Good accessibility: role="menu", role="menuitem", contextual aria-label, aria-hidden on icons
  • Proper cleanup of document event listeners
  • type="button" on all buttons to prevent form submission issues

The use of Tailwind semantic classes (text-foreground, bg-card, border-border, text-danger) aligns with coding guidelines.

Aureliolo and others added 8 commits March 27, 2026 15:30
Implement the Org Chart page (#778) with real-time organizational
visualization using React Flow. The chart shows agent nodes with
living status encoding (active/idle/error/offline), department
grouping with health overlays, auto-layout via dagre, and CRUD
operations via context menus.

Key components:
- AgentNode/CeoNode: custom React Flow nodes with Avatar + StatusBadge
- DepartmentGroupNode: health-colored group with stats bar
- HierarchyEdge: styled smooth-step edges
- OrgChartToolbar: view toggle, zoom, fit-view controls
- NodeContextMenu: right-click context menu with CRUD stubs
- OrgChartSkeleton: tree-like loading placeholder

Data layer:
- useCompanyStore: company config + department health
- useAgentsStore: runtime status overlay from WebSocket
- useOrgChartData: composite hook (stores + WS + polling)
- buildOrgTree: pure function deriving hierarchy from seniority
- applyDagreLayout: dagre wrapper for auto-positioning

Includes 30 new tests and 7 Storybook story files.

Closes #674

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Pre-reviewed by 5 agents, 15 findings addressed:

- Replace window.location.href with useNavigate (SPA navigation)
- Add onNodeClick handler for click-to-drill agent detail
- Add viewMode feedback toast for unimplemented force view
- Validate viewport shape from localStorage after JSON.parse
- Validate WebSocket payload at runtime before store update
- Use SeniorityLevel type instead of string in AgentNodeData
- Remove dead if/else branch in layout.ts
- Fix in-place array mutation in layout.ts (use Map instead)
- Add aria-label to AgentNode, CeoNode, DepartmentGroupNode
- Replace raw shadow CSS with Tailwind token in CeoNode
- Update CLAUDE.md stores/hooks descriptions
- Add store tests for useAgentsStore and useCompanyStore
- Add loading-with-nodes and c_suite fallback test cases

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…mini

- Type safety: extract getNodeLabel/getAgentName helpers, use Record<SeniorityLevel>
  instead of Record<string>, add VALID_NODE_TYPES guard, defensive node data access
- CEO context menu: separate ceoItems (View Details only) instead of inheriting
  agent CRUD actions like "Remove Agent"
- Empty departments: render in org chart even without agents (supports CRUD flow)
- Nullable health: department healthPercent/taskCount are null when API data missing
  instead of falsely defaulting to 100%/0
- Currency fix: DepartmentStatsBar defaults to 'USD' matching costUsd field semantics
- Store fix: fetchDepartmentHealths uses config.departments instead of listDepartments
  pagination, sets error state on failure instead of console.warn
- Tailwind v4: postfix important syntax (bg-accent! not !bg-accent)
- Layout: extract GROUP_NODE_HEADER_HEIGHT constant, replace min-w-[140px] with min-w-36
- Accessibility: aria-pressed on toolbar toggle buttons, type="button" on menu items
- Stories: add parameters.a11y.test:'error' to all 7 story metas, add CeoNode
  Error/Offline stories, add CeoMenu story, remove inline background style
- Tests: fix mock isolation (beforeEach reset in NodeContextMenu, factory in Toolbar),
  precise assertion toHaveLength(4), add agent.fired event test, use it.each for stats
- Comments: fix inaccurate agentName->teamLeadName, system->agent lifecycle events,
  memoized->stable reference, add JSDoc explaining active->idle mapping, ESLint
  suppress justification
- Docs: add @dagrejs/dagre to CLAUDE.md dependencies, fix test descriptions

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fix missing beforeEach import in NodeContextMenu test
- Sequence initial data fetch: await fetchCompanyData before
  fetchDepartmentHealths (health depends on config being loaded)
- Skip duplicate team membership in buildOrgTree (first team wins)
- Remove unnecessary shallow copy in findDepartmentHead when ceo is null
- Place empty department groups on a grid instead of all at (0,0)
- Don't set viewMode to 'force' since it's unimplemented (show toast only)
- Use Button asChild + Link instead of nested Link > Button (a11y)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add outside-click dismissal test for NodeContextMenu
- Add fast-check property-based test for menu structure invariants
- Guard fetchDepartmentHealths on config presence after fetchCompanyData
- Remove agents.length === 0 early return so department-only orgs render
- Offset empty department groups from laid-out content bounds

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add JSDoc to findCeo and findHighestSeniority documenting that ties
  are broken by array order (first wins)
- Fix leafNodes.length === 0 early return in applyDagreLayout to place
  department-only nodes on a grid instead of all at (0,0)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… chrome spacing

- Use EMPTY_GROUP_HEIGHT (120px) matching DepartmentGroupNode's min-h-[120px]
- Increase dagre nodeSep/rankSep when department groups exist to prevent
  overlapping group chrome (padding + header)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Aureliolo and others added 7 commits March 27, 2026 15:31
- errors.property.test.ts: mock axios to prevent fetch adapter capability
  detection (creates unresolved ReadableStream promises that leak)
- DashboardPage.test.tsx: replace dynamic import with static import to
  avoid timeout under leak detection overhead, use getByLabelText for
  skeleton to avoid multiple role="status" match
- ActivityFeed.test.tsx: reduce fast-check numRuns from 20 to 10
- App.test.tsx: increase timeout to 10s for lazy-loaded route rendering

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Layout: empty-group and department-only grid branches now respect the
  direction option (LR swaps axes)
- errors.property.test.ts: mock axios to prevent fetch adapter promise leaks
- DashboardPage.test.tsx: static import instead of dynamic to avoid timeout
  under --detect-async-leaks, use getByLabelText for skeleton query
- ActivityFeed.test.tsx: reduce fast-check numRuns from 20 to 10
- App.test.tsx: increase timeout for lazy-loaded route rendering

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…layout

Split positionedGroups map into two passes: pure computation of group
bounds, then isolated child position adjustment. Eliminates side-effect
mutation of positionedLeafMap inside a .map() callback.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- NodeContextMenu: cast e.target as Node (not HTMLElement) for contains()
- OrgChartToolbar.stories: set component to OrgChartToolbar so autodocs
  reflect the real props, use render for interactive wrapper
- company store: catch fetchCompanyData promise in WS handler to prevent
  unhandled rejection

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- NodeContextMenu: clamp position to viewport bounds to prevent overflow,
  add aria-label for screen readers
- company store: chain fetchDepartmentHealths after fetchCompanyData in
  WS handler so health data stays current on agent hire/fire events

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…uccess

- NodeContextMenu: distinguish CEO with "CEO actions" aria-label,
  clamp position to all four viewport edges (not just right/bottom)
- company store: clear error on successful health fetch so stale
  health errors don't persist after recovery

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- company store: detect when all department health fetches fail and set
  error instead of clearing it with empty array
- agents test: fix CoordinationTopology and updated_at type mismatches

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@Aureliolo Aureliolo force-pushed the feat/org-chart-page branch from 4203a61 to fd3ff57 Compare March 27, 2026 14:33
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

♻️ Duplicate comments (4)
web/src/__tests__/pages/dashboard/ActivityFeed.test.tsx (1)

54-54: ⚠️ Potential issue | 🟡 Minor

Restore stronger property-test coverage or make run count environment-aware.

Reducing numRuns from 20 to 10 cuts randomized coverage by 50%, weakening confidence in the cap-at-10 invariant. Consider keeping 20 runs in CI while allowing 10 for local development.

🔧 Proposed fix: environment-aware run count
-      { numRuns: 10 },
+      { numRuns: process.env.CI ? 20 : 10 },
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/__tests__/pages/dashboard/ActivityFeed.test.tsx` at line 54, The test
reduced randomized coverage by setting the test option { numRuns: 10 } in
ActivityFeed.test.tsx; restore stronger coverage by making numRuns
environment-aware: replace the hard-coded 10 with a value derived from an env
var (e.g., process.env.TEST_RUNS) or use process.env.CI to select 20 for CI and
10 locally, so the unique symbol "numRuns" in ActivityFeed.test.tsx drives the
run count dynamically and preserves 20 runs in CI while allowing 10 for local
dev.
web/src/pages/org/OrgChartToolbar.stories.tsx (1)

5-16: 🧹 Nitpick | 🔵 Trivial

Story args are defined but not wired through the render function.

The Default.args (Lines 31-38) are ignored because InteractiveToolbar doesn't accept any arguments and render (Line 25) doesn't pass args through. This means Storybook Controls won't affect the rendered component.

♻️ Wire args through InteractiveToolbar
-function InteractiveToolbar() {
-  const [viewMode, setViewMode] = useState<ViewMode>('hierarchy')
+type ToolbarProps = React.ComponentProps<typeof OrgChartToolbar>
+
+function InteractiveToolbar(args: Partial<ToolbarProps>) {
+  const [viewMode, setViewMode] = useState<ViewMode>(args.viewMode ?? 'hierarchy')
   return (
     <OrgChartToolbar
       viewMode={viewMode}
-      onViewModeChange={setViewMode}
-      onFitView={() => {}}
-      onZoomIn={() => {}}
-      onZoomOut={() => {}}
+      onViewModeChange={(mode) => {
+        setViewMode(mode)
+        args.onViewModeChange?.(mode)
+      }}
+      onFitView={args.onFitView ?? (() => {})}
+      onZoomIn={args.onZoomIn ?? (() => {})}
+      onZoomOut={args.onZoomOut ?? (() => {})}
     />
   )
 }

And update the render:

-  render: () => <InteractiveToolbar />,
+  render: (args) => <InteractiveToolbar {...args} />,

Also applies to: 25-25, 31-38

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/pages/org/OrgChartToolbar.stories.tsx` around lines 5 - 16, The
story's Default.args are not used because InteractiveToolbar is not receiving or
forwarding story args; modify InteractiveToolbar to accept props (e.g., args)
and spread or pass them into OrgChartToolbar (ensure viewMode and handlers are
taken from args or merged with local state as needed), and update the story
render function to call InteractiveToolbar with those args (so render: (args) =>
<InteractiveToolbar {...args} /> or similar). Reference InteractiveToolbar,
OrgChartToolbar, Default.args and render when making the change.
web/src/hooks/useOrgChartData.ts (1)

46-50: ⚠️ Potential issue | 🟡 Minor

Invalid ESLint disable comment has no effect.

The comment references @eslint-react/exhaustive-deps, but this rule doesn't exist in @eslint-react/eslint-plugin. The exhaustive-deps rule comes from eslint-plugin-react-hooks.

Either:

  1. Remove the disable comment if exhaustive-deps checking is not enabled, or
  2. Install eslint-plugin-react-hooks and change to // eslint-disable-next-line react-hooks/exhaustive-deps
♻️ Option 1: Remove ineffective comment
   useEffect(() => {
     polling.start()
     return () => polling.stop()
-    // eslint-disable-next-line `@eslint-react/exhaustive-deps` -- mount-only effect; polling.start/stop are stable but reference identity triggers false positive
   }, [])
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/hooks/useOrgChartData.ts` around lines 46 - 50, The ESLint disable
comment on the useEffect in useOrgChartData.ts is incorrect (refs
`@eslint-react/exhaustive-deps`) and has no effect; either remove the disable
comment or replace it with the correct rule name. Locate the useEffect that
calls polling.start() and returns polling.stop() and either delete the trailing
eslint-disable-next-line comment or change it to "// eslint-disable-next-line
react-hooks/exhaustive-deps" after ensuring eslint-plugin-react-hooks is
configured/installed so the rule will be recognized.
web/src/pages/org/AgentNode.stories.tsx (1)

11-11: 🛠️ Refactor suggestion | 🟠 Major

Replace hardcoded inline dimensions with Tailwind sizing classes.

The wrapper uses hardcoded pixel values in inline styles, which violates the coding guidelines.

♻️ Proposed fix
-      <div style={{ width: 400, height: 200 }}>
+      <div className="h-52 w-96">

As per coding guidelines: Use density-aware spacing tokens or standard Tailwind spacing; NEVER hardcode pixel values for layout spacing.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/pages/org/AgentNode.stories.tsx` at line 11, The story contains a div
with inline styles `style={{ width: 400, height: 200 }}`; remove the hardcoded
pixel styles and replace them with equivalent Tailwind sizing classes (use
appropriate w- and h- classes or project density-aware spacing tokens) in the
AgentNode story wrapper so layout uses Tailwind tokens instead of pixels.
🤖 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/__tests__/pages/org/build-org-tree.test.ts`:
- Around line 144-174: Add a regression test in build-org-tree.test.ts that
covers equal-seniority peers: create a fixture using makeAgent and makeConfig
with three same-level agents in one department (e.g., CEO, CTO, CFO all level
'c_suite' or two VPs same level), call buildOrgTree(config, {}, []), and assert
the deterministic tie-break behavior by checking result.edges for the expected
sources/targets (use result.edges.filter(e => e.source === 'ceo') or similar and
compare targets with a sorted array to avoid ordering flakiness). This ensures
buildOrgTree's first-wins tie rule is locked down for same-level peers.

In `@web/src/__tests__/pages/org/DepartmentStatsBar.test.tsx`:
- Around line 7-15: The parameterized it.each test repeatedly re-renders
DepartmentStatsBar with identical props; replace the it.each block (the test
titled 'renders %s with label %s') by a single test that renders
<DepartmentStatsBar agentCount={5} activeCount={3} taskCount={8} costUsd={null}
/> once and then asserts all three value/label pairs via multiple
expect(screen.getByText(...)).toBeInTheDocument() calls for '5'/'Agents',
'3'/'Active', and '8'/'Tasks' to keep coverage while avoiding redundant renders.

In `@web/src/__tests__/stores/company.test.ts`:
- Around line 99-124: The tests for useCompanyStore.getState().updateFromWsEvent
currently only assert fetchCompanyData (mockGetCompanyConfig) was called; update
the two agent.hired and agent.fired tests to also assert that
fetchDepartmentHealths triggers getDepartmentHealth by mocking/resolving the
department-health call (e.g., mockGetDepartmentHealth) and using vi.waitFor to
expect mockGetDepartmentHealth toHaveBeenCalled after calling updateFromWsEvent;
reference the functions updateFromWsEvent,
fetchCompanyData/fetchDepartmentHealths and the mocks
mockGetCompanyConfig/mockGetDepartmentHealth to locate and extend the
assertions.

In `@web/src/hooks/useOrgChartData.ts`:
- Around line 40-50: The polling currently starts immediately (polling.start()),
causing fetchDepartmentHealths() to run before fetchCompanyData() completes;
instead, start polling only after the initial fetchCompanyData() has finished.
Move the call to polling.start() out of the mount-only useEffect and invoke it
after await useCompanyStore.getState().fetchCompanyData() (or in the .then
callback) so pollFn/useCompanyStore.getState().fetchDepartmentHealths() runs
only once post-initial-fetch; still ensure polling.stop() is called on unmount
to clean up.

In `@web/src/pages/org/build-org-tree.ts`:
- Around line 168-175: The current fallback creates a hierarchy edge for any
non-team member (using head, agent, edges and id `e-${head.id}-${agent.id}`)
even when head and agent are same seniority; change the condition so you only
push that edge when head has strictly higher seniority/level than agent (e.g.,
check head.level > agent.level or head.seniority > agent.seniority), and skip
creating the manager/subordinate link when levels are equal (leave peers
unparented or handle via explicit business-rule function like
determineReportingRelationship(head, agent) if needed).

In `@web/src/pages/org/DepartmentGroupNode.stories.tsx`:
- Line 11: The wrapper div in DepartmentGroupNode.stories.tsx uses hardcoded
inline pixel styles (width: 500, height: 200); replace those inline styles with
appropriate Tailwind sizing classes on that wrapper (e.g., use density-aware /
standard Tailwind tokens such as w-96 h-48 or the project-specific spacing
tokens) by removing the style={{ width: 500, height: 200 }} and adding a
className with the chosen Tailwind sizes; keep the node's own style prop (the
React Flow node style mentioned in the comment) as-is since React Flow requires
explicit node dimensions.

In `@web/src/pages/OrgChartPage.tsx`:
- Around line 221-231: The error banners in OrgChartPage (the conditional blocks
rendering when error and when !wsConnected && wsSetupError) are not announced to
assistive tech; update those divs in the OrgChartPage component to include
appropriate live-region attributes (e.g., role="alert" or aria-live="assertive"
for the error banner and role="status" or aria-live="polite" for the websocket
warning) so screen readers announce the messages, and ensure any decorative
icons keep aria-hidden="true" (AlertTriangle already has aria-hidden) to avoid
duplicate announcements.

In `@web/src/stores/company.ts`:
- Around line 53-64: The websocket handler updateFromWsEvent triggers concurrent
fetchCompanyData → fetchDepartmentHealths chains; add a fetch-in-progress guard
or debounce in the company store to serialize these calls: introduce a boolean
(e.g., isFetchingCompany) or a simple mutex in the store used by
updateFromWsEvent (obtained via useCompanyStore.getState()) so if a fetch is
already running you either skip starting another fetch or coalesce subsequent
events, and ensure fetchCompanyData awaits completion before calling
fetchDepartmentHealths; update updateFromWsEvent to check/set the guard and to
clear it on success/failure to prevent race conditions and stale overwrites.

---

Duplicate comments:
In `@web/src/__tests__/pages/dashboard/ActivityFeed.test.tsx`:
- Line 54: The test reduced randomized coverage by setting the test option {
numRuns: 10 } in ActivityFeed.test.tsx; restore stronger coverage by making
numRuns environment-aware: replace the hard-coded 10 with a value derived from
an env var (e.g., process.env.TEST_RUNS) or use process.env.CI to select 20 for
CI and 10 locally, so the unique symbol "numRuns" in ActivityFeed.test.tsx
drives the run count dynamically and preserves 20 runs in CI while allowing 10
for local dev.

In `@web/src/hooks/useOrgChartData.ts`:
- Around line 46-50: The ESLint disable comment on the useEffect in
useOrgChartData.ts is incorrect (refs `@eslint-react/exhaustive-deps`) and has no
effect; either remove the disable comment or replace it with the correct rule
name. Locate the useEffect that calls polling.start() and returns polling.stop()
and either delete the trailing eslint-disable-next-line comment or change it to
"// eslint-disable-next-line react-hooks/exhaustive-deps" after ensuring
eslint-plugin-react-hooks is configured/installed so the rule will be
recognized.

In `@web/src/pages/org/AgentNode.stories.tsx`:
- Line 11: The story contains a div with inline styles `style={{ width: 400,
height: 200 }}`; remove the hardcoded pixel styles and replace them with
equivalent Tailwind sizing classes (use appropriate w- and h- classes or project
density-aware spacing tokens) in the AgentNode story wrapper so layout uses
Tailwind tokens instead of pixels.

In `@web/src/pages/org/OrgChartToolbar.stories.tsx`:
- Around line 5-16: The story's Default.args are not used because
InteractiveToolbar is not receiving or forwarding story args; modify
InteractiveToolbar to accept props (e.g., args) and spread or pass them into
OrgChartToolbar (ensure viewMode and handlers are taken from args or merged with
local state as needed), and update the story render function to call
InteractiveToolbar with those args (so render: (args) => <InteractiveToolbar
{...args} /> or similar). Reference InteractiveToolbar, OrgChartToolbar,
Default.args and render when making the change.
🪄 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: fb1e4d09-7707-4792-9d9d-255d5a86a701

📥 Commits

Reviewing files that changed from the base of the PR and between 4203a61 and fd3ff57.

⛔ Files ignored due to path filters (1)
  • web/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (39)
  • CLAUDE.md
  • web/package.json
  • web/src/__tests__/App.test.tsx
  • web/src/__tests__/pages/DashboardPage.test.tsx
  • web/src/__tests__/pages/dashboard/ActivityFeed.test.tsx
  • web/src/__tests__/pages/org/DepartmentStatsBar.test.tsx
  • web/src/__tests__/pages/org/NodeContextMenu.test.tsx
  • web/src/__tests__/pages/org/OrgChartPage.test.tsx
  • web/src/__tests__/pages/org/OrgChartSkeleton.test.tsx
  • web/src/__tests__/pages/org/OrgChartToolbar.test.tsx
  • web/src/__tests__/pages/org/build-org-tree.test.ts
  • web/src/__tests__/pages/org/layout.test.ts
  • web/src/__tests__/pages/org/status-mapping.test.ts
  • web/src/__tests__/stores/agents.test.ts
  • web/src/__tests__/stores/company.test.ts
  • web/src/__tests__/utils/errors.property.test.ts
  • web/src/hooks/useOrgChartData.ts
  • web/src/pages/OrgChartPage.tsx
  • web/src/pages/org/AgentNode.stories.tsx
  • web/src/pages/org/AgentNode.tsx
  • web/src/pages/org/CeoNode.stories.tsx
  • web/src/pages/org/CeoNode.tsx
  • web/src/pages/org/DepartmentGroupNode.stories.tsx
  • web/src/pages/org/DepartmentGroupNode.tsx
  • web/src/pages/org/DepartmentStatsBar.stories.tsx
  • web/src/pages/org/DepartmentStatsBar.tsx
  • web/src/pages/org/HierarchyEdge.tsx
  • web/src/pages/org/NodeContextMenu.stories.tsx
  • web/src/pages/org/NodeContextMenu.tsx
  • web/src/pages/org/OrgChartSkeleton.stories.tsx
  • web/src/pages/org/OrgChartSkeleton.tsx
  • web/src/pages/org/OrgChartToolbar.stories.tsx
  • web/src/pages/org/OrgChartToolbar.tsx
  • web/src/pages/org/build-org-tree.ts
  • web/src/pages/org/layout.ts
  • web/src/pages/org/status-mapping.ts
  • web/src/stores/agents.ts
  • web/src/stores/company.ts
  • web/src/styles/global.css
📜 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). (1)
  • GitHub Check: Build Web
🧰 Additional context used
📓 Path-based instructions (2)
web/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

web/src/**/*.{ts,tsx}: ALWAYS reuse existing components from web/src/components/ui/ (StatusBadge, MetricCard, Sparkline, SectionCard, AgentCard, etc.) before creating new ones
Use Tailwind semantic classes (text-foreground, bg-card, text-accent, etc.) or CSS variables (var(--so-*)) for colors; NEVER hardcode hex or rgba values
Use font-sans or font-mono for typography; NEVER set fontFamily directly in component code
Use density-aware spacing tokens (p-card, gap-section-gap, gap-grid-gap) or standard Tailwind spacing; NEVER hardcode pixel values for layout spacing
Use token variables for shadows and borders (var(--so-shadow-card-hover), border-border, border-bright); NEVER hardcode values
Do NOT recreate status dots inline -- use <StatusBadge>; do NOT build card-with-header layouts from scratch -- use <SectionCard>; do NOT create metric displays with hardcoded styles -- use <MetricCard>
Do NOT create complex (>8 line) JSX inside .map() -- extract to a shared component in web/src/components/ui/
Use TypeScript 6.0+ strict mode with proper tsconfig.json configuration: remove deprecated baseUrl, enable paths for imports, explicitly list types, use moduleResolution: 'bundler', keep strict: true
Set parameters.a11y.test: 'error' | 'todo' | 'off' in Storybook stories to enforce WCAG compliance (set globally in preview.tsx)

Files:

  • web/src/__tests__/pages/dashboard/ActivityFeed.test.tsx
  • web/src/__tests__/pages/DashboardPage.test.tsx
  • web/src/__tests__/pages/org/OrgChartSkeleton.test.tsx
  • web/src/__tests__/App.test.tsx
  • web/src/__tests__/utils/errors.property.test.ts
  • web/src/pages/org/OrgChartSkeleton.tsx
  • web/src/__tests__/pages/org/DepartmentStatsBar.test.tsx
  • web/src/pages/org/HierarchyEdge.tsx
  • web/src/pages/org/status-mapping.ts
  • web/src/pages/org/OrgChartSkeleton.stories.tsx
  • web/src/pages/org/DepartmentStatsBar.tsx
  • web/src/__tests__/pages/org/status-mapping.test.ts
  • web/src/__tests__/pages/org/OrgChartPage.test.tsx
  • web/src/__tests__/pages/org/OrgChartToolbar.test.tsx
  • web/src/pages/org/OrgChartToolbar.stories.tsx
  • web/src/stores/agents.ts
  • web/src/pages/org/CeoNode.tsx
  • web/src/pages/org/AgentNode.tsx
  • web/src/hooks/useOrgChartData.ts
  • web/src/__tests__/pages/org/NodeContextMenu.test.tsx
  • web/src/__tests__/stores/agents.test.ts
  • web/src/pages/org/NodeContextMenu.tsx
  • web/src/pages/org/DepartmentGroupNode.tsx
  • web/src/pages/org/DepartmentGroupNode.stories.tsx
  • web/src/__tests__/stores/company.test.ts
  • web/src/pages/org/NodeContextMenu.stories.tsx
  • web/src/pages/org/OrgChartToolbar.tsx
  • web/src/pages/org/AgentNode.stories.tsx
  • web/src/__tests__/pages/org/build-org-tree.test.ts
  • web/src/__tests__/pages/org/layout.test.ts
  • web/src/pages/org/CeoNode.stories.tsx
  • web/src/stores/company.ts
  • web/src/pages/org/DepartmentStatsBar.stories.tsx
  • web/src/pages/org/build-org-tree.ts
  • web/src/pages/OrgChartPage.tsx
  • web/src/pages/org/layout.ts
web/src/**/*.stories.tsx

📄 CodeRabbit inference engine (CLAUDE.md)

Storybook stories must cover all component states (default, hover, loading, error, empty) and be created alongside the component in web/src/components/ui/

Files:

  • web/src/pages/org/OrgChartSkeleton.stories.tsx
  • web/src/pages/org/OrgChartToolbar.stories.tsx
  • web/src/pages/org/DepartmentGroupNode.stories.tsx
  • web/src/pages/org/NodeContextMenu.stories.tsx
  • web/src/pages/org/AgentNode.stories.tsx
  • web/src/pages/org/CeoNode.stories.tsx
  • web/src/pages/org/DepartmentStatsBar.stories.tsx
🧠 Learnings (28)
📓 Common learnings
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/).
📚 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/src/__tests__/pages/dashboard/ActivityFeed.test.tsx
  • web/src/__tests__/pages/DashboardPage.test.tsx
  • web/src/__tests__/pages/org/OrgChartSkeleton.test.tsx
  • web/src/__tests__/utils/errors.property.test.ts
  • CLAUDE.md
  • web/src/__tests__/pages/org/DepartmentStatsBar.test.tsx
  • web/src/__tests__/pages/org/status-mapping.test.ts
  • web/src/__tests__/pages/org/OrgChartPage.test.tsx
  • web/src/__tests__/pages/org/OrgChartToolbar.test.tsx
  • web/src/__tests__/pages/org/NodeContextMenu.test.tsx
  • web/src/__tests__/stores/company.test.ts
  • web/src/__tests__/pages/org/build-org-tree.test.ts
  • web/src/__tests__/pages/org/layout.test.ts
📚 Learning: 2026-03-27T14:30:49.093Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T14:30:49.093Z
Learning: Applies to web/src/**/*.{ts,tsx} : Use Tailwind semantic classes (`text-foreground`, `bg-card`, `text-accent`, etc.) or CSS variables (`var(--so-*)`) for colors; NEVER hardcode hex or rgba values

Applied to files:

  • web/src/styles/global.css
  • web/src/pages/org/OrgChartSkeleton.stories.tsx
  • web/src/pages/org/CeoNode.tsx
  • web/src/pages/org/AgentNode.tsx
  • web/src/pages/org/AgentNode.stories.tsx
  • web/src/pages/OrgChartPage.tsx
📚 Learning: 2026-03-27T14:30:49.093Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T14:30:49.093Z
Learning: Applies to web/src/**/*.{ts,tsx} : Use token variables for shadows and borders (`var(--so-shadow-card-hover)`, `border-border`, `border-bright`); NEVER hardcode values

Applied to files:

  • web/src/styles/global.css
  • web/src/pages/org/OrgChartSkeleton.stories.tsx
  • web/src/pages/org/CeoNode.tsx
  • web/src/pages/org/AgentNode.tsx
  • web/src/pages/org/AgentNode.stories.tsx
  • web/src/pages/OrgChartPage.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
  • CLAUDE.md
  • web/src/pages/org/CeoNode.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: 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:

  • web/package.json
  • CLAUDE.md
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to src/synthorg/**/*.py : Package structure: src/synthorg/ organized as: api/ (REST+WebSocket, Litestar), auth/ (auth subpackage), backup/ (scheduled/manual backups), budget/ (cost tracking, CFO), cli/ (superseded by Go CLI), communication/ (message bus, meetings), config/ (YAML loading), core/ (domain models, resilience config), engine/ (orchestration, task state, coordination, approval gates, stagnation detection, context budget, compaction), hr/ (hiring, performance, promotion), memory/ (pluggable backend, Mem0, retrieval, consolidation), persistence/ (operational data, SQLite, settings), observability/ (logging, correlation, sinks), providers/ (LLM abstraction, LiteLLM, auth types, presets, runtime CRUD), settings/ (runtime-editable, typed definitions, encryption, config bridge), security/ (SecOps, rule engine, output scanning, progressive trust, autonomy levels), templates/ (company templates, personalities), tools/ (registry, built-in tools, git, sandbox, code_runner, MCP...

Applied to files:

  • CLAUDE.md
📚 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:

  • CLAUDE.md
  • web/src/pages/org/DepartmentStatsBar.tsx
  • web/src/pages/org/build-org-tree.ts
📚 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 docs/** : Docs source in docs/ (Markdown, built with Zensical); design spec in docs/design/ (7 pages: index, agents, organization, communication, engine, memory, operations)

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: Applies to pyproject.toml : Dependencies: all versions use == in pyproject.toml. Groups: test (pytest + plugins, hypothesis), dev (includes test + ruff, mypy, pre-commit, commitizen, pip-audit). Required: mem0ai (Mem0 memory backend — the default and currently only backend). Install: uv sync installs everything (dev group is default).

Applied to files:

  • CLAUDE.md
📚 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: Go 1.26+ required; CLI dependencies in `cli/go.mod` (Cobra, charmbracelet/huh, charmbracelet/lipgloss, sigstore-go, go-containerregistry, go-tuf)

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: 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:

  • 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: Applies to go.mod : Maintain Go 1.26+ requirement. Dependencies: Cobra (CLI framework), charmbracelet/huh and charmbracelet/lipgloss (UI), sigstore-go (code signing), go-containerregistry (container image verification), go-tuf (TUF client for Sigstore).

Applied to files:

  • CLAUDE.md
📚 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: Applies to cli/go.mod : CLI uses Go 1.26+. Dependencies: Cobra, charmbracelet/huh, charmbracelet/lipgloss, sigstore-go, go-containerregistry, go-tuf

Applied to files:

  • CLAUDE.md
📚 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 cli/**/*.go : Go CLI (Go 1.26+) uses Cobra for commands, charmbracelet/huh for interactive CLI, charmbracelet/lipgloss for styled output. Cross-platform builds (linux/darwin/windows × amd64/arm64). GoReleaser for releases with cosign keyless signing of checksums.txt. SLSA L3 provenance attestations via actions/attest-build-provenance.

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: Applies to cli/** : CLI: Go 1.26+, dependencies in cli/go.mod (Cobra, charmbracelet/huh).

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-27T14:30:49.093Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T14:30:49.093Z
Learning: Applies to web/src/**/*.{ts,tsx} : Do NOT recreate status dots inline -- use `<StatusBadge>`; do NOT build card-with-header layouts from scratch -- use `<SectionCard>`; do NOT create metric displays with hardcoded styles -- use `<MetricCard>`

Applied to files:

  • web/src/pages/org/OrgChartSkeleton.tsx
  • web/src/__tests__/pages/org/DepartmentStatsBar.test.tsx
  • web/src/pages/org/OrgChartSkeleton.stories.tsx
  • web/src/pages/org/DepartmentStatsBar.tsx
  • web/src/pages/org/OrgChartToolbar.stories.tsx
  • web/src/pages/org/CeoNode.tsx
  • web/src/pages/org/AgentNode.tsx
  • web/src/pages/org/DepartmentGroupNode.tsx
  • web/src/pages/org/DepartmentGroupNode.stories.tsx
  • web/src/pages/org/AgentNode.stories.tsx
  • web/src/pages/org/DepartmentStatsBar.stories.tsx
  • web/src/pages/OrgChartPage.tsx
  • web/src/pages/org/layout.ts
📚 Learning: 2026-03-19T07:13:44.964Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:13:44.964Z
Learning: Applies to src/synthorg/hr/**/*.py : HR package (hr/): hiring, firing, onboarding, offboarding, agent registry, performance tracking (task metrics, collaboration scoring, LLM calibration, collaboration overrides, trend detection), promotion/demotion (criteria evaluation, approval strategies, model mapping)

Applied to files:

  • web/src/pages/org/status-mapping.ts
📚 Learning: 2026-03-16T06:24:56.341Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-16T06:24:56.341Z
Learning: Applies to src/synthorg/hr/**/*.py : HR engine must provide: hiring, firing, onboarding, offboarding, agent registry, performance tracking (task metrics, collaboration scoring, trend detection), promotion/demotion

Applied to files:

  • web/src/pages/org/status-mapping.ts
📚 Learning: 2026-03-27T14:30:49.093Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T14:30:49.093Z
Learning: Applies to web/src/**/*.stories.tsx : Storybook stories must cover all component states (default, hover, loading, error, empty) and be created alongside the component in `web/src/components/ui/`

Applied to files:

  • web/src/pages/org/OrgChartSkeleton.stories.tsx
  • web/src/pages/org/OrgChartToolbar.stories.tsx
  • web/src/pages/org/DepartmentGroupNode.stories.tsx
  • web/src/pages/org/NodeContextMenu.stories.tsx
  • web/src/pages/org/AgentNode.stories.tsx
  • web/src/pages/org/CeoNode.stories.tsx
  • web/src/pages/org/DepartmentStatsBar.stories.tsx
📚 Learning: 2026-03-27T14:30:49.093Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T14:30:49.093Z
Learning: Applies to web/src/components/ui/*.tsx : Create new shared components in `web/src/components/ui/` with a descriptive kebab-case filename, a corresponding `.stories.tsx` Storybook file, and a TypeScript interface for props

Applied to files:

  • web/src/pages/org/OrgChartSkeleton.stories.tsx
  • web/src/pages/org/OrgChartToolbar.stories.tsx
  • web/src/__tests__/pages/org/NodeContextMenu.test.tsx
  • web/src/pages/org/DepartmentGroupNode.stories.tsx
  • web/src/pages/org/NodeContextMenu.stories.tsx
  • web/src/pages/org/AgentNode.stories.tsx
  • web/src/pages/org/CeoNode.stories.tsx
  • web/src/pages/org/DepartmentStatsBar.stories.tsx
📚 Learning: 2026-03-27T14:30:49.093Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T14:30:49.093Z
Learning: Applies to web/src/**/*.{ts,tsx} : Set `parameters.a11y.test: 'error' | 'todo' | 'off'` in Storybook stories to enforce WCAG compliance (set globally in `preview.tsx`)

Applied to files:

  • web/src/pages/org/OrgChartSkeleton.stories.tsx
  • web/src/__tests__/pages/org/OrgChartToolbar.test.tsx
  • web/src/pages/org/OrgChartToolbar.stories.tsx
  • web/src/__tests__/pages/org/NodeContextMenu.test.tsx
  • web/src/pages/org/DepartmentGroupNode.stories.tsx
  • web/src/pages/org/NodeContextMenu.stories.tsx
  • web/src/pages/org/OrgChartToolbar.tsx
  • web/src/pages/org/AgentNode.stories.tsx
  • web/src/pages/org/CeoNode.stories.tsx
  • web/src/pages/org/DepartmentStatsBar.stories.tsx
📚 Learning: 2026-03-27T14:30:49.093Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T14:30:49.093Z
Learning: Applies to web/.storybook/**/*.{ts,tsx} : Use Storybook 10+ API: `defineMain` from `storybook/react-vite/node` for `main.ts`, `definePreview` from `storybook/react-vite` for `preview.tsx`, import from `storybook/*` (not `storybook/*`), use `parameters.backgrounds.options` object + `initialGlobals.backgrounds.value`

Applied to files:

  • web/src/pages/org/OrgChartSkeleton.stories.tsx
  • web/src/pages/org/OrgChartToolbar.stories.tsx
  • web/src/pages/org/DepartmentGroupNode.stories.tsx
  • web/src/pages/org/NodeContextMenu.stories.tsx
  • web/src/pages/org/AgentNode.stories.tsx
  • web/src/pages/org/CeoNode.stories.tsx
  • web/src/pages/org/DepartmentStatsBar.stories.tsx
📚 Learning: 2026-03-27T14:30:49.093Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T14:30:49.093Z
Learning: Applies to web/src/**/*.{ts,tsx} : ALWAYS reuse existing components from `web/src/components/ui/` (StatusBadge, MetricCard, Sparkline, SectionCard, AgentCard, etc.) before creating new ones

Applied to files:

  • web/src/pages/org/DepartmentStatsBar.tsx
  • web/src/pages/org/AgentNode.tsx
  • web/src/pages/org/AgentNode.stories.tsx
📚 Learning: 2026-03-27T14:30:49.093Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T14:30:49.093Z
Learning: Applies to web/src/**/*.{ts,tsx} : Use density-aware spacing tokens (`p-card`, `gap-section-gap`, `gap-grid-gap`) or standard Tailwind spacing; NEVER hardcode pixel values for layout spacing

Applied to files:

  • web/src/pages/org/CeoNode.tsx
  • web/src/pages/org/AgentNode.tsx
  • web/src/pages/org/AgentNode.stories.tsx
  • web/src/pages/org/layout.ts
📚 Learning: 2026-03-27T14:30:49.093Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T14:30:49.093Z
Learning: Applies to web/src/components/ui/*.tsx : All new shared components must use design tokens exclusively -- no hardcoded colors, fonts, or spacing -- and import `cn` from `@/lib/utils` for conditional class merging

Applied to files:

  • web/src/pages/org/CeoNode.tsx
  • web/src/pages/org/AgentNode.tsx
  • web/src/pages/org/AgentNode.stories.tsx
  • web/src/pages/OrgChartPage.tsx
📚 Learning: 2026-03-27T14:30:49.093Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T14:30:49.093Z
Learning: Applies to web/src/**/*.{ts,tsx} : Use TypeScript 6.0+ strict mode with proper `tsconfig.json` configuration: remove deprecated `baseUrl`, enable `paths` for imports, explicitly list `types`, use `moduleResolution: 'bundler'`, keep `strict: true`

Applied to files:

  • web/src/pages/org/CeoNode.tsx
📚 Learning: 2026-03-27T14:30:49.093Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T14:30:49.093Z
Learning: Applies to web/src/**/*.{ts,tsx} : Do NOT create complex (>8 line) JSX inside `.map()` -- extract to a shared component in `web/src/components/ui/`

Applied to files:

  • web/src/pages/org/AgentNode.tsx
  • web/src/pages/org/AgentNode.stories.tsx
  • web/src/pages/OrgChartPage.tsx
  • web/src/pages/org/layout.ts
🔇 Additional comments (42)
web/src/__tests__/App.test.tsx (1)

59-84: LGTM!

The reformatting and explicit per-test timeout of 10_000ms is a sensible improvement for test stability. The buffer between the inner waitFor timeout (5s) and the overall test timeout (10s) appropriately accounts for lazy-loaded module resolution overhead in concurrent test runs.

web/src/__tests__/pages/DashboardPage.test.tsx (3)

64-73: LGTM!

Good refactor. The comment accurately explains Vitest's mock hoisting behavior, and converting renderDashboard to synchronous is correct since dynamic imports are no longer needed. This simplifies the test code.


85-89: LGTM!

Using getByLabelText('Loading dashboard') is more specific than getByRole('status') since multiple elements could potentially have the status role. The aria-label uniquely identifies the dashboard skeleton, making the assertion more targeted and resilient.


80-144: LGTM!

Consistent removal of await across all test cases. The tests maintain good coverage of component states (loading, error, WebSocket status) and the synchronous pattern is correctly applied throughout.

web/package.json (2)

44-55: LGTM!

The @types/d3-hierarchy dev dependency addition is appropriate for providing TypeScript types for hierarchy/tree data structures used in the org chart layout utilities.


18-18: Package version is available. The @dagrejs/dagre version 3.0.0 exists on npm and is valid for use.

CLAUDE.md (2)

131-131: LGTM!

Documentation correctly updated to reflect the new company and agents Zustand stores added for the org chart feature.


323-323: LGTM!

Documentation updated to include @dagrejs/dagre in the web dashboard dependencies, keeping it in sync with the web/package.json changes.

web/src/__tests__/utils/errors.property.test.ts (2)

5-14: LGTM!

The axios mock effectively prevents async leaks from the fetch adapter capability detection. The mock correctly provides isAxiosError on the default export, which is what axios.isAxiosError() resolves to in the actual code.

Note: The named isAxiosError export (lines 12-13) is technically redundant since errors.ts only calls axios.isAxiosError via the default import wrapper, but having it doesn't cause harm and provides extra safety if the import pattern changes.


16-25: LGTM!

The makeFakeAxiosError helper cleanly creates AxiosError-shaped objects without importing the real class, avoiding the async leak issues. The property test correctly verifies that 5xx error messages never leak response body content — an important security invariant.

Also applies to: 37-49

web/src/pages/org/OrgChartSkeleton.tsx (1)

1-30: LGTM!

Well-implemented skeleton component that:

  • Correctly reuses SkeletonCard from @/components/ui/skeleton
  • Provides proper accessibility with role="status", aria-live="polite", and aria-label
  • Uses standard Tailwind spacing tokens (gap-6, gap-8, pt-12)
  • Visually represents the org chart hierarchy structure
web/src/pages/org/OrgChartSkeleton.stories.tsx (1)

1-23: LGTM!

Story follows Storybook 10 conventions correctly:

  • Uses satisfies Meta<typeof OrgChartSkeleton> for type safety
  • Sets parameters.a11y.test: 'error' for WCAG compliance enforcement
  • Decorator provides necessary height for the vertical layout
  • Past review comment about inline background style was addressed

For a skeleton component, the "Default" story is appropriate since skeletons represent a single loading state rather than multiple interactive states.

web/src/__tests__/pages/org/OrgChartSkeleton.test.tsx (1)

1-20: LGTM!

Focused test suite that verifies the critical accessibility attributes of the skeleton component:

  • role="status" for live region semantics
  • aria-live="polite" for non-intrusive screen reader announcements
  • Accessible label text for context
web/src/pages/org/CeoNode.tsx (1)

1-52: LGTM!

Well-structured React Flow node component that:

  • Correctly reuses Avatar and StatusBadge from @/components/ui/
  • Uses Tailwind semantic classes (text-foreground, bg-card, text-muted-foreground, border-accent/30)
  • Uses cn() for class merging
  • Properly memoized for React Flow performance
  • Includes accessibility attributes (data-testid, aria-label)
  • Uses Tailwind v4 postfix important syntax (bg-accent!, size-1.5!) correctly
web/src/pages/org/DepartmentStatsBar.tsx (1)

1-30: LGTM!

Clean implementation that:

  • Correctly reuses StatPill from @/components/ui/
  • Defaults currency to 'USD' to match costUsd field semantics (past review addressed)
  • Conditionally renders Cost only when costUsd !== null
  • Uses cn() for className merging
  • Uses standard Tailwind spacing (gap-1.5)
web/src/pages/org/DepartmentStatsBar.stories.tsx (1)

1-48: LGTM!

The stories file properly configures accessibility testing (a11y.test: 'error') and covers the key component states: default with all props, null cost handling, and zero-value edge case. The decorator constrains width for consistent rendering.

web/src/pages/org/CeoNode.stories.tsx (1)

1-100: LGTM!

Good coverage of all AgentRuntimeStatus values (active, idle, error, offline) with proper ReactFlow context setup. The a11y test configuration is correctly set to 'error'.

web/src/stores/company.ts (2)

22-30: LGTM!

The fetchCompanyData implementation correctly manages loading state, clears previous errors on start, and properly handles both success and failure paths.


32-51: LGTM!

The department health fetch correctly:

  • Guards against missing config
  • Uses .catch(() => null) to allow partial success
  • Filters out failed results
  • Sets an appropriate error when all departments fail
web/src/__tests__/stores/company.test.ts (2)

30-47: LGTM!

Good test isolation with beforeEach resetting store state to match the production initial state, and vi.clearAllMocks() ensuring no state leaks between tests.


80-97: LGTM!

Good coverage of partial failure handling - verifies that when one department health fetch fails, the successful result is still stored and the failed one is filtered out.

web/src/styles/global.css (1)

7-7: LGTM!

Importing React Flow's base styles is required for proper node/edge rendering and is correctly placed in the global stylesheet.

web/src/pages/org/HierarchyEdge.tsx (1)

1-27: LGTM!

Clean edge component implementation with proper memoization for React Flow performance. The stroke color correctly uses the CSS variable var(--color-border-bright) defined in global.css, maintaining theme consistency.

web/src/__tests__/pages/org/DepartmentStatsBar.test.tsx (1)

17-31: LGTM!

Good coverage of conditional rendering for the cost section and the data-testid attribute for integration testing.

web/src/pages/org/status-mapping.ts (1)

1-30: LGTM!

Clean utility module with well-documented functions. The switch statement handles all AgentStatus variants with appropriate fall-through for onboarding/active, and resolveRuntimeStatus correctly prioritizes WebSocket-pushed status over the HR-derived default.

web/src/__tests__/pages/org/OrgChartToolbar.test.tsx (1)

1-52: LGTM!

The test suite is well-structured with the createProps() factory function properly creating fresh mock instances per test, avoiding state leakage between tests. Good coverage of toolbar rendering and interaction handlers.

web/src/__tests__/pages/org/layout.test.ts (1)

1-104: LGTM!

Comprehensive test coverage for applyDagreLayout including empty inputs, position validation, sibling separation, directional ordering, department node handling, and graceful handling of dangling edges. The test descriptions accurately reflect the assertions.

web/src/__tests__/stores/agents.test.ts (1)

416-471: LGTM!

Excellent test coverage for the new runtime status functionality. The tests properly validate both the happy path (updateRuntimeStatus, valid WS events) and defensive cases (missing agent_id, missing status, invalid status values, non-status event types). This ensures robust handling of malformed WebSocket payloads.

web/src/stores/agents.ts (1)

216-235: LGTM!

The runtime status actions are well-implemented with proper defensive validation:

  • updateRuntimeStatus provides direct state updates
  • updateFromWsEvent validates event type, checks for required string fields, and validates status against the allowlist before updating state

The type assertion on Line 232 is safe because the VALID_RUNTIME_STATUSES.has(status) check guarantees the value is a valid AgentRuntimeStatus.

web/src/pages/org/NodeContextMenu.stories.tsx (1)

1-48: LGTM!

Good story coverage for all three node types (agent, department, ceo) with proper accessibility testing configuration (a11y.test: 'error'). The decorator provides appropriate container sizing for the context menu positioning.

web/src/__tests__/pages/org/status-mapping.test.ts (1)

1-43: LGTM!

Comprehensive test coverage for both status mapping functions. The edge case test at Line 39-42 (runtime override precedence over HR terminated status) is particularly valuable, documenting the expected behavior when WebSocket and HR data conflict.

web/src/pages/org/DepartmentGroupNode.tsx (2)

1-51: LGTM!

Clean implementation following coding guidelines:

  • Uses semantic Tailwind classes (text-foreground, text-muted-foreground, bg-card/50)
  • Proper typography classes (font-sans, font-mono)
  • Correctly handles nullable healthPercent and taskCount fields
  • Memoized for React Flow performance

The health color mapping and fallback logic is well-structured with the HEALTH_BG_CLASSES lookup.


35-35: text-micro is properly defined in the Tailwind configuration.

The class is generated via the @theme inline directive in web/src/styles/global.css, which declares --font-size-micro: var(--so-text-micro). Tailwind's @theme mechanism automatically creates the .text-micro utility from this declaration, and it's correctly backed by the design token --so-text-micro: 10px in design-tokens.css. No action needed.

			> Likely an incorrect or invalid review comment.
web/src/pages/org/AgentNode.tsx (1)

1-60: LGTM!

The component correctly:

  • Reuses StatusBadge and Avatar from shared UI components
  • Uses semantic Tailwind classes (text-foreground, bg-card, border-border)
  • Applies standard Tailwind spacing (min-w-36, max-w-44, px-3, py-2)
  • Provides accessible aria-label with agent context
  • Maps all possible getStatusColor return values in STATUS_RING_CLASSES

The previous concern about hardcoded pixel widths has been properly addressed.

web/src/__tests__/pages/org/OrgChartPage.test.tsx (1)

1-143: LGTM!

The test suite provides solid coverage for OrgChartPage UI states:

  • Loading skeleton display
  • Empty state handling
  • Error banner rendering
  • WebSocket disconnect warnings
  • Conditional rendering when nodes exist
  • Edge case: skeleton hidden when loading with existing nodes

The mock pattern with module-level variables reset in beforeEach ensures test isolation.

web/src/pages/org/AgentNode.stories.tsx (1)

55-69: Good coverage of runtime status variants.

The stories appropriately cover all runtimeStatus states (active, idle, error, offline) that drive the component's visual behavior (ring color, opacity, pulse animation).

web/src/pages/org/OrgChartToolbar.tsx (1)

1-88: LGTM!

The toolbar implementation is clean and accessible:

  • Proper toggle button pattern with aria-pressed state
  • All buttons have descriptive aria-label attributes
  • Icons marked aria-hidden="true"
  • Reuses the shared Button component
  • Uses semantic Tailwind classes throughout
web/src/hooks/useOrgChartData.ts (1)

69-75: LGTM!

The graph derivation is properly memoized with correct dependencies. The computation only reruns when config, runtimeStatuses, or departmentHealths change.

web/src/pages/org/DepartmentGroupNode.stories.tsx (1)

47-87: Good coverage of health status variants.

The stories appropriately cover the three health tiers (Healthy at 92%, Warning at 45%, Critical at 15%) and include the edge case where costUsd: null suppresses cost display.

web/src/pages/org/NodeContextMenu.tsx (1)

1-154: LGTM!

The component addresses all previous review concerns:

  • CEO nodes have dedicated menu items (lines 99-108)
  • Buttons have explicit type="button" (line 139)
  • Type cast uses Node for contains() check (line 48)
  • Menu has descriptive aria-label based on node type (line 133)
  • Position clamping handles all viewport edges with Math.max/Math.min (lines 120-121)
  • Menu labels distinguish between agent, CEO, and department

Accessibility is solid with role="menu", role="menuitem", and proper aria-label.

web/src/__tests__/pages/org/NodeContextMenu.test.tsx (1)

1-107: LGTM!

The test suite provides comprehensive coverage:

  • Tests for all node types (agent, department, ceo)
  • Callback verification (onViewDetails, onDelete)
  • Close behavior (Escape key, outside click)
  • ARIA structure validation
  • Property-based testing with fast-check verifying menu invariants across all node types

Previous concerns about mock reset, beforeEach import, and outside-click testing have all been addressed.

web/src/pages/OrgChartPage.tsx (1)

120-129: No changes needed – NodeContextMenu uses position: fixed which correctly aligns with viewport-relative coordinates from event.clientX/Y.

The menu is already positioned fixed to the viewport, so clientX/Y coordinates are appropriate. The implementation also includes viewport-bounds clamping to prevent overflow.

			> Likely an incorrect or invalid review comment.

Comment on lines +168 to +175
} else if (head && agent.id !== head.id) {
// Agent reports to department head
edges.push({
id: `e-${head.id}-${agent.id}`,
source: head.id,
target: agent.id,
type: 'hierarchy',
})
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Don't turn equal-seniority peers into manager/subordinate links.

This fallback attaches every non-team member to head, even when head only won a same-level tie by array order. In departments like [CEO, CTO, CFO] or [VP A, VP B], that makes one peer appear to manage another with no supporting data.

🧭 Minimal safeguard
-      } else if (head && agent.id !== head.id) {
+      } else if (
+        head &&
+        agent.id !== head.id &&
+        seniorityOf(agent.level) < seniorityOf(head.level)
+      ) {
         // Agent reports to department head
         edges.push({
           id: `e-${head.id}-${agent.id}`,
           source: head.id,
           target: agent.id,
           type: 'hierarchy',
         })
       }

This avoids fabricating peer-to-peer reporting lines. You can then decide separately whether equal-seniority peers should stay unparented or become direct reports via explicit business rules.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/pages/org/build-org-tree.ts` around lines 168 - 175, The current
fallback creates a hierarchy edge for any non-team member (using head, agent,
edges and id `e-${head.id}-${agent.id}`) even when head and agent are same
seniority; change the condition so you only push that edge when head has
strictly higher seniority/level than agent (e.g., check head.level > agent.level
or head.seniority > agent.seniority), and skip creating the manager/subordinate
link when levels are equal (leave peers unparented or handle via explicit
business-rule function like determineReportingRelationship(head, agent) if
needed).

function Wrapper({ data }: { data: DepartmentGroupData }) {
return (
<ReactFlowProvider>
<div style={{ width: 500, height: 200 }}>
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Replace hardcoded inline dimensions with Tailwind sizing classes.

The wrapper container uses hardcoded pixel values in inline styles.

♻️ Proposed fix
-      <div style={{ width: 500, height: 200 }}>
+      <div className="h-52 w-[500px]">

Note: The node's style prop (line 19) may need to remain as React Flow uses explicit dimensions for node sizing.

As per coding guidelines: Use density-aware spacing tokens or standard Tailwind spacing; NEVER hardcode pixel values for layout spacing.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/pages/org/DepartmentGroupNode.stories.tsx` at line 11, The wrapper
div in DepartmentGroupNode.stories.tsx uses hardcoded inline pixel styles
(width: 500, height: 200); replace those inline styles with appropriate Tailwind
sizing classes on that wrapper (e.g., use density-aware / standard Tailwind
tokens such as w-96 h-48 or the project-specific spacing tokens) by removing the
style={{ width: 500, height: 200 }} and adding a className with the chosen
Tailwind sizes; keep the node's own style prop (the React Flow node style
mentioned in the comment) as-is since React Flow requires explicit node
dimensions.

Comment on lines +53 to +64
updateFromWsEvent: (event) => {
// Handle agent lifecycle events that affect company structure
if (event.event_type === 'agent.hired' || event.event_type === 'agent.fired') {
// Re-fetch company config to get updated agent list
const store = useCompanyStore.getState()
store.fetchCompanyData()
.then(() => store.fetchDepartmentHealths())
.catch(() => {
// Errors are set in store state by the respective fetch methods
})
}
},
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Rapid WebSocket events can trigger concurrent fetches causing race conditions.

Per the dispatchEvent implementation in web/src/stores/websocket.ts (lines 93-104), channel handlers are invoked synchronously without throttling. Multiple agent.hired/agent.fired events arriving in quick succession will trigger concurrent fetchCompanyDatafetchDepartmentHealths chains, potentially causing stale responses to overwrite fresher data.

Consider debouncing or adding a fetch-in-progress guard:

🛡️ Proposed fix with in-flight guard
+  _fetchInProgress: false,
+
   updateFromWsEvent: (event) => {
     // Handle agent lifecycle events that affect company structure
     if (event.event_type === 'agent.hired' || event.event_type === 'agent.fired') {
+      if (useCompanyStore.getState()._fetchInProgress) return
+      set({ _fetchInProgress: true })
       // Re-fetch company config to get updated agent list
       const store = useCompanyStore.getState()
       store.fetchCompanyData()
         .then(() => store.fetchDepartmentHealths())
-        .catch(() => {
+        .finally(() => set({ _fetchInProgress: false }))
+        .catch(() => {
           // Errors are set in store state by the respective fetch methods
         })
     }
   },
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/stores/company.ts` around lines 53 - 64, The websocket handler
updateFromWsEvent triggers concurrent fetchCompanyData → fetchDepartmentHealths
chains; add a fetch-in-progress guard or debounce in the company store to
serialize these calls: introduce a boolean (e.g., isFetchingCompany) or a simple
mutex in the store used by updateFromWsEvent (obtained via
useCompanyStore.getState()) so if a fetch is already running you either skip
starting another fetch or coalesce subsequent events, and ensure
fetchCompanyData awaits completion before calling fetchDepartmentHealths; update
updateFromWsEvent to check/set the guard and to clear it on success/failure to
prevent race conditions and stale overwrites.

…live regions

- Add regression test for same-level peer tiebreaker (first-in-array wins)
- Consolidate DepartmentStatsBar tests into single render
- Assert fetchDepartmentHealths is called after WS agent events
- Start health polling only after initial fetchCompanyData completes
- Add role="alert" and role="status" aria-live to error/warning banners

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (1)
web/src/pages/OrgChartPage.tsx (1)

264-264: 🧹 Nitpick | 🔵 Trivial

Use the canonical var(--so-border) token.

Per coding guidelines, use var(--so-*) CSS variables directly rather than intermediate variables like --color-border.

🎨 Suggested fix
-          <Background color="var(--color-border)" gap={24} size={1} />
+          <Background color="var(--so-border)" gap={24} size={1} />

As per coding guidelines: "Use Tailwind semantic classes (text-foreground, bg-card, text-accent, etc.) or CSS variables (var(--so-*)) for colors; NEVER hardcode hex or rgba values"

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/pages/OrgChartPage.tsx` at line 264, The Background component in
OrgChartPage.tsx is using the non-canonical CSS variable --color-border; update
the prop to use the canonical semantic token var(--so-border) instead (keep the
same props gap={24} and size={1}) so the line reads Background color uses
var(--so-border) to conform with the so-* token guideline.
🤖 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/__tests__/pages/org/DepartmentStatsBar.test.tsx`:
- Around line 17-21: Add a test in DepartmentStatsBar.test.tsx that verifies the
optional currency prop is forwarded to formatCurrency: render
<DepartmentStatsBar agentCount={5} activeCount={3} taskCount={8} costUsd={100}
currency="EUR" /> (or another value), then assert
screen.getByText(formatCurrency(100, 'EUR')) and screen.getByText('Cost') are in
the document; this ensures DepartmentStatsBar and formatCurrency are exercised
with a non-default currency.

In `@web/src/hooks/useOrgChartData.ts`:
- Around line 51-61: The bindings in useOrgChartData are subscribing to
ORG_CHANNELS including the 'system' channel even though
useCompanyStore.updateFromWsEvent and useAgentsStore.updateFromWsEvent only
handle agent-related events; remove the unused subscription by filtering
ORG_CHANNELS to only include the 'agents' channel (or adjust ORG_CHANNELS
definition) before mapping to ChannelBinding so the handler in useOrgChartData
only subscribes to channels that those updateFromWsEvent methods actually
process.

---

Duplicate comments:
In `@web/src/pages/OrgChartPage.tsx`:
- Line 264: The Background component in OrgChartPage.tsx is using the
non-canonical CSS variable --color-border; update the prop to use the canonical
semantic token var(--so-border) instead (keep the same props gap={24} and
size={1}) so the line reads Background color uses var(--so-border) to conform
with the so-* token guideline.
🪄 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: 0a6d3c05-339c-4bb6-81a7-7703012ed6ed

📥 Commits

Reviewing files that changed from the base of the PR and between fd3ff57 and f63a7a3.

📒 Files selected for processing (5)
  • web/src/__tests__/pages/org/DepartmentStatsBar.test.tsx
  • web/src/__tests__/pages/org/build-org-tree.test.ts
  • web/src/__tests__/stores/company.test.ts
  • web/src/hooks/useOrgChartData.ts
  • web/src/pages/OrgChartPage.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 Backend
  • GitHub Check: Build Web
  • GitHub Check: Build Sandbox
  • GitHub Check: Dependency Review
  • GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (1)
web/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

web/src/**/*.{ts,tsx}: ALWAYS reuse existing components from web/src/components/ui/ (StatusBadge, MetricCard, Sparkline, SectionCard, AgentCard, etc.) before creating new ones
Use Tailwind semantic classes (text-foreground, bg-card, text-accent, etc.) or CSS variables (var(--so-*)) for colors; NEVER hardcode hex or rgba values
Use font-sans or font-mono for typography; NEVER set fontFamily directly in component code
Use density-aware spacing tokens (p-card, gap-section-gap, gap-grid-gap) or standard Tailwind spacing; NEVER hardcode pixel values for layout spacing
Use token variables for shadows and borders (var(--so-shadow-card-hover), border-border, border-bright); NEVER hardcode values
Do NOT recreate status dots inline -- use <StatusBadge>; do NOT build card-with-header layouts from scratch -- use <SectionCard>; do NOT create metric displays with hardcoded styles -- use <MetricCard>
Do NOT create complex (>8 line) JSX inside .map() -- extract to a shared component in web/src/components/ui/
Use TypeScript 6.0+ strict mode with proper tsconfig.json configuration: remove deprecated baseUrl, enable paths for imports, explicitly list types, use moduleResolution: 'bundler', keep strict: true
Set parameters.a11y.test: 'error' | 'todo' | 'off' in Storybook stories to enforce WCAG compliance (set globally in preview.tsx)

Files:

  • web/src/__tests__/pages/org/DepartmentStatsBar.test.tsx
  • web/src/hooks/useOrgChartData.ts
  • web/src/pages/OrgChartPage.tsx
  • web/src/__tests__/pages/org/build-org-tree.test.ts
  • web/src/__tests__/stores/company.test.ts
🧠 Learnings (10)
📓 Common learnings
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/).
📚 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/src/__tests__/pages/org/DepartmentStatsBar.test.tsx
  • web/src/__tests__/pages/org/build-org-tree.test.ts
  • web/src/__tests__/stores/company.test.ts
📚 Learning: 2026-03-27T14:30:49.093Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T14:30:49.093Z
Learning: Applies to web/src/**/*.{ts,tsx} : Do NOT recreate status dots inline -- use `<StatusBadge>`; do NOT build card-with-header layouts from scratch -- use `<SectionCard>`; do NOT create metric displays with hardcoded styles -- use `<MetricCard>`

Applied to files:

  • web/src/__tests__/pages/org/DepartmentStatsBar.test.tsx
  • web/src/pages/OrgChartPage.tsx
📚 Learning: 2026-03-27T14:30:49.093Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T14:30:49.093Z
Learning: Applies to web/src/components/ui/*.tsx : Create new shared components in `web/src/components/ui/` with a descriptive kebab-case filename, a corresponding `.stories.tsx` Storybook file, and a TypeScript interface for props

Applied to files:

  • web/src/__tests__/pages/org/DepartmentStatsBar.test.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/__tests__/pages/org/DepartmentStatsBar.test.tsx
📚 Learning: 2026-03-27T14:30:49.093Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T14:30:49.093Z
Learning: Applies to web/src/**/*.{ts,tsx} : Do NOT create complex (>8 line) JSX inside `.map()` -- extract to a shared component in `web/src/components/ui/`

Applied to files:

  • web/src/pages/OrgChartPage.tsx
📚 Learning: 2026-03-27T14:30:49.093Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T14:30:49.093Z
Learning: Applies to web/src/**/*.{ts,tsx} : Use token variables for shadows and borders (`var(--so-shadow-card-hover)`, `border-border`, `border-bright`); NEVER hardcode values

Applied to files:

  • web/src/pages/OrgChartPage.tsx
📚 Learning: 2026-03-27T14:30:49.093Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T14:30:49.093Z
Learning: Applies to web/src/**/*.{ts,tsx} : Use Tailwind semantic classes (`text-foreground`, `bg-card`, `text-accent`, etc.) or CSS variables (`var(--so-*)`) for colors; NEVER hardcode hex or rgba values

Applied to files:

  • web/src/pages/OrgChartPage.tsx
📚 Learning: 2026-03-27T14:30:49.093Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T14:30:49.093Z
Learning: Applies to web/src/components/ui/*.tsx : All new shared components must use design tokens exclusively -- no hardcoded colors, fonts, or spacing -- and import `cn` from `@/lib/utils` for conditional class merging

Applied to files:

  • web/src/pages/OrgChartPage.tsx
📚 Learning: 2026-03-27T14:30:49.093Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T14:30:49.093Z
Learning: Applies to web/src/**/*.{ts,tsx} : Set `parameters.a11y.test: 'error' | 'todo' | 'off'` in Storybook stories to enforce WCAG compliance (set globally in `preview.tsx`)

Applied to files:

  • web/src/pages/OrgChartPage.tsx
🔇 Additional comments (11)
web/src/__tests__/pages/org/DepartmentStatsBar.test.tsx (2)

7-15: LGTM! Previous feedback addressed.

The consolidated test correctly implements the refactor suggested in the previous review: a single render with multiple assertions for all stat values and labels. This is more efficient than the previous parameterized approach while maintaining full coverage.


1-32: Well-structured test suite.

The test suite appropriately covers the component's functionality:

  • ✅ All stat pills render with correct values and labels
  • ✅ Cost conditional rendering (present when provided, absent when null)
  • ✅ Data-testid presence
  • ✅ Correct use of getByText for presence and queryByText for absence assertions
  • ✅ Integration with formatCurrency utility matches component implementation
web/src/__tests__/stores/company.test.ts (1)

1-142: LGTM!

The test suite provides comprehensive coverage for useCompanyStore:

  • Initial state verification
  • fetchCompanyData success and failure paths
  • fetchDepartmentHealths with config present, missing, and partial failures
  • updateFromWsEvent behavior for agent lifecycle events (now correctly verifying both getCompanyConfig and getDepartmentHealth are called) and unrelated events

The previous review comment about verifying the full re-fetch chain has been addressed in lines 99-131.

web/src/__tests__/pages/org/build-org-tree.test.ts (1)

1-332: LGTM!

Comprehensive test suite covering all key behaviors of buildOrgTree:

  • CEO identification with multiple fallback strategies
  • Department grouping and agent nesting via parentId
  • Edge generation for hierarchy relationships
  • Filtering of terminated agents
  • Health data enrichment and runtime status overrides
  • Team-based hierarchy derivation with deduplication

The previous review comments have been addressed:

  • Lines 158-175 add the regression test for same-level peer tie-breaking
  • Lines 307-317 no longer have the redundant spread assignment
web/src/hooks/useOrgChartData.ts (2)

36-48: Sequencing and polling initialization look correct.

The initial fetch correctly:

  1. Calls fetchCompanyData() first
  2. Only calls fetchDepartmentHealths() if config exists (line 41)
  3. Starts polling after initial fetch completes (line 44)
  4. Stops polling on unmount (line 46)

This addresses the previous review comments about fetch sequencing and polling races.


47-47: The ESLint rule name in the disable comment is correct. The codebase uses @eslint-react/eslint-plugin (as documented in web/eslint.config.js lines 7-8), not eslint-plugin-react-hooks. The @eslint-react/exhaustive-deps rule is the valid rule name for this configuration and is used consistently across multiple files in the codebase. No change is needed.

			> Likely an incorrect or invalid review comment.
web/src/pages/OrgChartPage.tsx (5)

43-49: Good defensive pattern for extracting agent name.

The getAgentName helper correctly validates the node type and checks that name is a string before returning, preventing runtime errors from malformed node data. This addresses the previous review comment about adding a runtime guard.


174-187: View mode change handler correctly gates the unimplemented communication view.

The handler returns early for mode === 'force' without calling setViewMode, keeping the toolbar state consistent with the rendered view. This addresses the previous review comment.


221-232: Accessibility attributes correctly applied to error banners.

The error banner uses role="alert" (line 222) and the WebSocket warning uses role="status" with aria-live="polite" (line 228), ensuring screen readers announce these async failures. This addresses the previous review comment about announcing failures to assistive tech.


296-301: Correct Button/Link composition using asChild.

The asChild prop correctly delegates rendering to the Link child, avoiding nested interactive elements. This addresses the previous review comment about invalid HTML semantics.


51-53: Stable reference identity for node/edge types.

Declaring nodeTypes and edgeTypes outside the component prevents unnecessary re-renders of the ReactFlow canvas. This is a React Flow best practice.

…bscription

- DepartmentStatsBar: add test for explicit currency prop forwarding
- useOrgChartData: remove 'system' from ORG_CHANNELS since neither store
  handler processes system channel events

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@Aureliolo Aureliolo merged commit 0acbdae into main Mar 27, 2026
29 checks passed
@Aureliolo Aureliolo deleted the feat/org-chart-page branch March 27, 2026 15:17
Aureliolo added a commit that referenced this pull request Mar 30, 2026
🤖 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-&gt;3 and @types/node 22-&gt;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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: Org Chart page (living nodes, status, CRUD, department health) feat: interactive org chart with department/team CRUD and detail pages

1 participant