Skip to content

fix: align frontend types with backend and debounce WS refetches#916

Merged
Aureliolo merged 8 commits intomainfrom
fix/type-alignment-websocket
Mar 30, 2026
Merged

fix: align frontend types with backend and debounce WS refetches#916
Aureliolo merged 8 commits intomainfrom
fix/type-alignment-websocket

Conversation

@Aureliolo
Copy link
Copy Markdown
Owner

Summary

  • fix: align frontend DepartmentHealth type with backend model #892: Align DepartmentHealth type with backend model -- rename name->department_name, health_percent->utilization_percent, cost_usd->department_cost_7d; remove display_name and task_count; add active_agent_count, currency, avg_performance_score, cost_trend, collaboration_score. Cascade to 20+ consumer files including DeptHealthBar (remove taskCount prop), DepartmentStatsBar, DepartmentGroupData, stores, tests, and stories.
  • fix: align frontend AgentConfig type with actual backend API response shape #878: Align AgentConfig type with backend -- make id/status/hiring_date optional (runtime fields from AgentIdentity), remove skills (unused), change typed sub-objects to Record<string, unknown>, add required authority field. All consumers use fallbacks (agent.id ?? agent.name, agent.status ?? 'active'). Remove dead interfaces (PersonalityConfig, ModelConfig, SkillSet, MemoryConfig, ToolPermissions).
  • refactor: add ActivityEventType literal union for type-safe event matching #877: Define ActivityEventType literal union (13 values) with (string & {}) extensibility pattern. Type-narrow ACTIVITY_ICON_MAP to Partial<Record<ActivityEventType, LucideIcon>>.
  • fix: debounce WebSocket-triggered refetches in agent hooks #876: Add 300ms debounce to WebSocket event handlers in useAgentsData and useAgentDetailData to coalesce burst events into a single API refetch. Uses useRef for timeout handle with cleanup on unmount.

Test plan

  • npm --prefix web run type-check -- zero errors
  • npm --prefix web run lint -- zero warnings
  • npm --prefix web run test -- 2101 tests pass (12 new)
  • New debounce tests: sync suppression, 300ms firing, burst coalescing, unmount cleanup, cross-channel coalescing
  • New fallback tests: agent.id: undefined falls back to agent.name, agent.status: undefined treated as 'active'
  • Visual: Dashboard dept health bars render with utilization %
  • Visual: Org Chart dept nodes show correct metrics
  • Visual: Agent cards render with optional status/hiring_date
  • Visual: Activity timeline icons map correctly
  • Visual: Rapid WS events produce single refetch (network tab)

Pre-reviewed by 5 agents (frontend-reviewer, type-design-analyzer, test-analyzer, docs-consistency, issue-resolution-verifier), 11 findings addressed.

Closes #892
Closes #878
Closes #877
Closes #876

🤖 Generated with Claude Code

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 29, 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: e09c2fa5-eb30-4654-a326-8fa26fbe569b

📥 Commits

Reviewing files that changed from the base of the PR and between df79937 and a0ebc9c.

📒 Files selected for processing (3)
  • docs/design/brand-and-ux.md
  • web/src/__tests__/pages/org/build-org-tree.test.ts
  • web/src/pages/agents/AgentGridView.stories.tsx
📜 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). (5)
  • GitHub Check: Build Backend
  • GitHub Check: Build Web
  • GitHub Check: Dashboard Test
  • GitHub Check: Dependency Review
  • GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (8)
web/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

web/src/**/*.{ts,tsx}: Web Dashboard: ALWAYS reuse existing components from web/src/components/ui/ before creating new ones. Reuse StatusBadge, MetricCard, Sparkline, SectionCard, AgentCard, DeptHealthBar, ProgressGauge, StatPill, Avatar, Button, Toast, Skeleton variants, EmptyState, ErrorBoundary, ConfirmDialog, CommandPalette, InlineEdit, AnimatedPresence, StaggerGroup, Drawer, InputField, SelectField, SliderField, ToggleField, TaskStatusIndicator, PriorityBadge, ProviderHealthBadge, TokenUsageBar, CodeMirrorEditor, SegmentedControl, ThemeToggle.
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 text-metric font-bold—use <MetricCard>. Do NOT render initials circles manually—use <Avatar>. Do NOT create complex (>8 line) JSX inside .map()—extract to a shared component.
Web design system enforcement: A PostToolUse hook (scripts/check_web_design_system.py) runs automatically on every Edit/Write to web/src/ files. It catches hardcoded hex colors, rgba values, font-family declarations, missing Storybook stories, duplicate patterns, and complex map blocks. Fix all violations before proceeding.
React 19 + shadcn/ui + Tailwind CSS 4 dashboard: Use React Router, Zustand stores, @tanstack/react-query, @xyflow/react, @dagrejs/dagre, d3-force, @dnd-kit, Recharts, Framer Motion, cmdk, js-yaml, Axios.

Files:

  • web/src/pages/agents/AgentGridView.stories.tsx
  • web/src/__tests__/pages/org/build-org-tree.test.ts
web/src/**/*.{ts,tsx,css}

📄 CodeRabbit inference engine (CLAUDE.md)

Design tokens: Colors use Tailwind semantic classes (text-foreground, bg-card, text-accent, etc.) or CSS variables (var(--so-accent)). NEVER hardcode hex values. Typography uses font-sans or font-mono. Spacing uses density-aware tokens or standard Tailwind. Shadows/borders use token variables.

Files:

  • web/src/pages/agents/AgentGridView.stories.tsx
  • web/src/__tests__/pages/org/build-org-tree.test.ts
**/*.{ts,tsx,json}

📄 CodeRabbit inference engine (CLAUDE.md)

TypeScript 6.0: Remove baseUrl (deprecated); paths entries are relative to tsconfig directory. esModuleInterop always true—cannot be set to false. types defaults to []—must explicitly list (e.g. 'types': ['vitest/globals']). DOM.Iterable merged into DOM. moduleResolution: 'classic' and 'node10' removed—use 'bundler' or 'nodenext'. strict defaults to true. noUncheckedSideEffectImports defaults to true.

Files:

  • web/src/pages/agents/AgentGridView.stories.tsx
  • web/src/__tests__/pages/org/build-org-tree.test.ts
web/**/*.stories.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Storybook 10: ESM-only—no CJS support. Packages like @storybook/addon-essentials, @storybook/addon-interactions, @storybook/test, @storybook/blocks no longer published. @storybook/addon-docs is separate. Import from storybook/test (not @storybook/test), storybook/actions. Use defineMain from @storybook/react-vite/node and definePreview from @storybook/react-vite. Backgrounds API: use parameters.backgrounds.options (object) + initialGlobals.backgrounds.value. a11y testing: use parameters.a11y.test: 'error' | 'todo' | 'off'. Minimum versions: Node 20.19+, Vite 5+, Vitest 3+, TypeScript 4.9+.

Files:

  • web/src/pages/agents/AgentGridView.stories.tsx
**/*.{py,ts,tsx,go}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{py,ts,tsx,go}: Lint & format: Python via ruff (uv run ruff check + uv run ruff format). TypeScript web via ESLint (zero warnings enforced: npm --prefix web run lint). Go CLI via golangci-lint and go vet. All enforced in pre-commit hooks.
Type checking: Python via mypy strict mode (uv run mypy src/ tests/). TypeScript via npm --prefix web run type-check. Go via go -C cli vet ./....

Files:

  • web/src/pages/agents/AgentGridView.stories.tsx
  • web/src/__tests__/pages/org/build-org-tree.test.ts
web/src/pages/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Web dashboard pages: Lazy-loaded page components (one per route). Page-scoped sub-components in pages/<page-name>/ subdirs. Feature dirs added as pages are built. Stores for auth, WebSocket, toast, analytics, setup wizard, company, agents, budget, tasks, settings, providers, theme.

Files:

  • web/src/pages/agents/AgentGridView.stories.tsx
docs/design/*.md

📄 CodeRabbit inference engine (CLAUDE.md)

When approved deviations occur, update the relevant docs/design/ page to reflect the new reality.

Files:

  • docs/design/brand-and-ux.md
docs/**/*.md

📄 CodeRabbit inference engine (CLAUDE.md)

Documentation: docs/ (Markdown, built with Zensical, config: mkdocs.yml). Design spec in docs/design/ (11 pages), architecture in docs/architecture/, roadmap in docs/roadmap/. REST API reference auto-generated by scripts/export_openapi.py. Library reference auto-generated via mkdocstrings + Griffe. Landing page in site/ (Astro).

Files:

  • docs/design/brand-and-ux.md
🧠 Learnings (8)
📓 Common learnings
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-29T11:41:44.483Z
Learning: Applies to web/src/**/*.{ts,tsx} : Web Dashboard: ALWAYS reuse existing components from `web/src/components/ui/` before creating new ones. Reuse StatusBadge, MetricCard, Sparkline, SectionCard, AgentCard, DeptHealthBar, ProgressGauge, StatPill, Avatar, Button, Toast, Skeleton variants, EmptyState, ErrorBoundary, ConfirmDialog, CommandPalette, InlineEdit, AnimatedPresence, StaggerGroup, Drawer, InputField, SelectField, SliderField, ToggleField, TaskStatusIndicator, PriorityBadge, ProviderHealthBadge, TokenUsageBar, CodeMirrorEditor, SegmentedControl, ThemeToggle.
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-29T11:41:44.483Z
Learning: Applies to web/src/**/*.{ts,tsx} : React 19 + shadcn/ui + Tailwind CSS 4 dashboard: Use React Router, Zustand stores, tanstack/react-query, xyflow/react, dagrejs/dagre, d3-force, dnd-kit, Recharts, Framer Motion, cmdk, js-yaml, Axios.
📚 Learning: 2026-03-29T11:41:44.483Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-29T11:41:44.483Z
Learning: Applies to web/**/*.stories.{ts,tsx} : Storybook 10: ESM-only—no CJS support. Packages like `storybook/addon-essentials`, `storybook/addon-interactions`, `storybook/test`, `storybook/blocks` no longer published. `storybook/addon-docs` is separate. Import from `storybook/test` (not `storybook/test`), `storybook/actions`. Use `defineMain` from `storybook/react-vite/node` and `definePreview` from `storybook/react-vite`. Backgrounds API: use `parameters.backgrounds.options` (object) + `initialGlobals.backgrounds.value`. a11y testing: use `parameters.a11y.test: 'error' | 'todo' | 'off'`. Minimum versions: Node 20.19+, Vite 5+, Vitest 3+, TypeScript 4.9+.

Applied to files:

  • web/src/pages/agents/AgentGridView.stories.tsx
📚 Learning: 2026-03-29T11:41:44.482Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-29T11:41:44.482Z
Learning: Applies to docs/design/*.md : When approved deviations occur, update the relevant `docs/design/` page to reflect the new reality.

Applied to files:

  • docs/design/brand-and-ux.md
📚 Learning: 2026-03-29T11:41:44.483Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-29T11:41:44.483Z
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 `text-metric font-bold`—use `<MetricCard>`. Do NOT render initials circles manually—use `<Avatar>`. Do NOT create complex (>8 line) JSX inside `.map()`—extract to a shared component.

Applied to files:

  • docs/design/brand-and-ux.md
📚 Learning: 2026-03-29T11:41:44.483Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-29T11:41:44.483Z
Learning: Applies to web/src/**/*.{ts,tsx} : Web Dashboard: ALWAYS reuse existing components from `web/src/components/ui/` before creating new ones. Reuse StatusBadge, MetricCard, Sparkline, SectionCard, AgentCard, DeptHealthBar, ProgressGauge, StatPill, Avatar, Button, Toast, Skeleton variants, EmptyState, ErrorBoundary, ConfirmDialog, CommandPalette, InlineEdit, AnimatedPresence, StaggerGroup, Drawer, InputField, SelectField, SliderField, ToggleField, TaskStatusIndicator, PriorityBadge, ProviderHealthBadge, TokenUsageBar, CodeMirrorEditor, SegmentedControl, ThemeToggle.

Applied to files:

  • docs/design/brand-and-ux.md
📚 Learning: 2026-03-29T11:41:44.483Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-29T11:41:44.483Z
Learning: Applies to web/src/**/*.{ts,tsx,css} : Design tokens: Colors use Tailwind semantic classes (`text-foreground`, `bg-card`, `text-accent`, etc.) or CSS variables (`var(--so-accent)`). NEVER hardcode hex values. Typography uses `font-sans` or `font-mono`. Spacing uses density-aware tokens or standard Tailwind. Shadows/borders use token variables.

Applied to files:

  • docs/design/brand-and-ux.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:

  • docs/design/brand-and-ux.md
📚 Learning: 2026-03-20T08:28:32.845Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-20T08:28:32.845Z
Learning: Applies to web/src/__tests__/**/*.{ts,js} : Dashboard testing: Vitest unit tests organized by feature under `web/src/__tests__/`. Use fast-check for property-based testing (`fc.assert` + `fc.property`).

Applied to files:

  • web/src/__tests__/pages/org/build-org-tree.test.ts
🔇 Additional comments (10)
web/src/pages/agents/AgentGridView.stories.tsx (2)

33-33: Good fixture update for required AgentConfig.authority.

authority: {} is a correct default for the updated required field and keeps the factory aligned with the backend-shaped type.


52-52: A11y test parameter is configured correctly.

Setting parameters.a11y.test to 'error' is valid and improves story-level accessibility enforcement.

As per coding guidelines: "a11y testing: use parameters.a11y.test: 'error' | 'todo' | 'off'."

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

7-7: Good fixture typing for optional id.

makeAgent now models optional id correctly while keeping name required, matching the updated AgentConfig contract.


32-32: Required authority is correctly added to test fixtures.

This keeps test data aligned with the backend-facing AgentConfig shape.


55-63: Department health fixture is correctly migrated to backend field names.

The new fields (department_name, department_cost_7d, utilization_percent, etc.) are consistent with the target model.


222-223: Assertions correctly validate mapped cost7d and currency.

This matches the current DepartmentGroupData mapping behavior.


307-308: Null-path assertions are updated correctly for missing health data.

Validating cost7d and currency as null here is the right expectation.


337-349: Great coverage for agent.id fallback behavior.

This test directly verifies the agent.id ?? agent.name fallback used to build node identity.


351-365: Good regression test for undefined status defaulting to active.

This captures the intended filter semantics and protects against accidental exclusion of status-less agents.

docs/design/brand-and-ux.md (1)

203-203: LGTM! Documentation correctly updated to reflect component changes.

The DeptHealthBar entry now accurately documents the updated component:

  • Props list correctly shows taskCount removed (leaving name, health?, agentCount)
  • Description consistently uses "utilization" terminology throughout ("utilization percentage", "utilization unavailable")
  • Addresses the past review concern about mixing "health" and "utilization" terminology

Walkthrough

This PR aligns frontend types and consumers with backend models and debounces WebSocket-triggered refetches. DepartmentHealth was reshaped to backend fields (department_name, utilization_percent, department_cost_7d, currency, active_agent_count, etc.). AgentConfig now uses untyped Record fields for sub-objects, makes id/status/hiring_date optional, removes skills, and adds authority. An ActivityEventType literal union and ACTIVITY_EVENT_TYPE_VALUES were added. DeptHealthBar dropped the taskCount prop and relabels its meter as utilization. Numerous tests, stories, fixtures, and consumers were updated to the new shapes and debounce behavior.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 17.07% 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 PR title clearly summarizes the main changes: aligning frontend types with backend and debouncing WebSocket refetches, matching the core objectives.
Description check ✅ Passed The PR description is detailed and directly related to the changeset, covering all four linked issues (#892, #878, #877, #876) with specific scope and implementation details.
Linked Issues check ✅ Passed All code changes align with linked issue requirements: DepartmentHealth schema updated [#892], AgentConfig fields made optional with fallbacks [#878], ActivityEventType defined [#877], WebSocket debouncing added [#876].
Out of Scope Changes check ✅ Passed All changes are in-scope: type updates, consumer cascades, test updates, story fixtures, and debounce implementations directly support the four linked issues.

✏️ 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.

@Aureliolo Aureliolo temporarily deployed to cloudflare-preview March 29, 2026 20:28 — with GitHub Actions Inactive
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 refactors the AgentConfig and DepartmentHealth API types to align with the backend schema, transitioning several structured fields to generic Record<string, unknown> types and renaming health metrics to utilization. It introduces WebSocket debouncing in the useAgentsData and useAgentDetailData hooks to coalesce burst events and prevent excessive refetching. Additionally, the UI components and test suites have been updated to handle optional agent fields and the new data structures. Feedback focuses on improving type safety when accessing properties on the now-generic tools and model objects by using bracket notation and explicit type checks.


<ErrorBoundary level="section">
<ToolBadges tools={[...agent.tools.allowed]} />
<ToolBadges tools={Array.isArray(agent.tools.allowed) ? (agent.tools.allowed as unknown[]).filter((t): t is string => typeof t === 'string') : []} />
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

While this defensive check is great, accessing properties on a Record<string, unknown> using dot notation isn't type-safe and can be flagged by stricter TypeScript rules. Using bracket notation (['allowed']) is safer and more explicit about accessing a dynamic property.

Suggested change
<ToolBadges tools={Array.isArray(agent.tools.allowed) ? (agent.tools.allowed as unknown[]).filter((t): t is string => typeof t === 'string') : []} />
<ToolBadges tools={Array.isArray(agent.tools['allowed']) ? (agent.tools['allowed'] as unknown[]).filter((t): t is string => typeof t === 'string') : []} />

<div className="border-t border-border pt-4 space-y-2">
<p className="text-xs font-semibold uppercase tracking-wider text-text-muted">Model</p>
<p className="text-xs text-text-secondary font-mono">{agent.model.provider} / {agent.model.model_id}</p>
<p className="text-xs text-text-secondary font-mono">{String(agent.model.provider ?? '')} / {String(agent.model.model_id ?? '')}</p>
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

This is a good defensive measure. However, using dot notation on a Record<string, unknown> is not type-safe. It's better to use bracket notation. Also, String(value) can produce "[object Object]" if value is an object. A typeof check would be more robust.

Suggested change
<p className="text-xs text-text-secondary font-mono">{String(agent.model.provider ?? '')} / {String(agent.model.model_id ?? '')}</p>
<p className="text-xs text-text-secondary font-mono">{(typeof agent.model['provider'] === 'string' ? agent.model['provider'] : '')} / {(typeof agent.model['model_id'] === 'string' ? agent.model['model_id'] : '')}</p>

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 29, 2026

Dependency Review

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

Snapshot Warnings

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

Scanned Files

None

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (4)
web/src/hooks/useAgentDetailData.ts (1)

96-116: ⚠️ Potential issue | 🟠 Major

Handle agentName transitions in the WS lifecycle.

useWebSocket only re-runs its setup when enabled changes; it intentionally ignores later bindings changes. With the current agentName ? ... : EMPTY_BINDINGS branch, mounting this hook with an empty name never installs handlers when the name appears later, and switching back to an empty name leaves the old handlers live until unmount. Because the timer is also only cleared on unmount, a queued callback can still fire after navigation and call fetchAgentDetail('').

Please tie the socket lifecycle to agentName and clear any pending debounce when agentName changes, not just on unmount. A rerender test for '' -> 'alice' -> '' would lock this down.

🔧 Minimal fix
-  useEffect(() => () => {
-    if (wsDebounceRef.current) clearTimeout(wsDebounceRef.current)
-  }, [])
+  useEffect(() => {
+    if (!agentName && wsDebounceRef.current) {
+      clearTimeout(wsDebounceRef.current)
+      wsDebounceRef.current = null
+    }
+
+    return () => {
+      if (wsDebounceRef.current) {
+        clearTimeout(wsDebounceRef.current)
+        wsDebounceRef.current = null
+      }
+    }
+  }, [agentName])
...
-  const { connected: wsConnected, setupError: wsSetupError } = useWebSocket({ bindings })
+  const { connected: wsConnected, setupError: wsSetupError } = useWebSocket({
+    bindings,
+    enabled: Boolean(agentName),
+  })
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/hooks/useAgentDetailData.ts` around lines 96 - 116, The socket
handlers currently never get installed/removed when agentName transitions
because useWebSocket ignores later bindings changes; fix by tying the socket
lifecycle to agentName and clearing pending debounce on name changes: pass
enabled: Boolean(agentName) into useWebSocket({ bindings, enabled: !!agentName
}) so the hook sets up/tears down when agentName changes, and add a useEffect
that watches agentName and on change clears any pending timeout on
wsDebounceRef.current (and optionally resets agentNameRef.current) to prevent
fetchAgentDetail('') from firing; keep DETAIL_CHANNELS, bindings, wsDebounceRef,
useEffect, useWebSocket, fetchAgentDetail and agentNameRef references to locate
where to modify.
web/src/pages/org-edit/AgentsTab.tsx (1)

168-177: ⚠️ Potential issue | 🔴 Critical

Backend endpoint for reordering agents is not implemented.

The frontend code (lines 172-173) sends agent IDs to POST /departments/{name}/reorder-agents, but this endpoint does not exist in the backend. The DepartmentController has only read-only endpoints (@get). This will cause the reorder operation to fail with a 404 error at runtime.

Additionally, when agent.id is undefined, the code falls back to agent.name, which may not be a valid agent identifier from the backend's perspective (the backend likely expects UUIDs or stable IDs, not human-readable names).

Implement the missing /departments/{name}/reorder-agents endpoint in the backend, and ensure it validates that all agent identifiers in agent_ids are actual IDs, not names. Filter out or reject agents without valid IDs before processing the reorder request.

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

In `@web/src/pages/org-edit/AgentsTab.tsx` around lines 168 - 177, Add a POST
handler on the backend to implement the /departments/{name}/reorder-agents
endpoint: add a method (e.g., reorderAgents) to DepartmentController that
accepts a body { agent_ids: string[] }, validates each entry is a valid agent ID
(e.g., UUID format) and belongs to the given department, rejects with 400 if any
ID is missing/invalid (do not accept names as IDs), and calls a service method
(e.g., DepartmentService.reorderAgents(departmentName, agentIds)) to persist the
new order; ensure the controller returns appropriate success/error responses and
that DepartmentService updates the stored order for that department atomically.
web/src/__tests__/stores/company.test.ts (1)

390-407: ⚠️ Potential issue | 🟡 Minor

Assertions still miss the optional-ID fallback path

agentIds now use a.id ?? a.name, but Lines [400] and [406] still assert a.id only. This won’t validate reorder behavior for agents without id.

🧪 Proposed test fix
-      expect(reordered.map((a) => a.id)).toEqual(agentIds)
+      expect(reordered.map((a) => a.id ?? a.name)).toEqual(agentIds)
...
-      expect(restored.map((a) => a.id)).toEqual(agentIds.toReversed())
+      expect(restored.map((a) => a.id ?? a.name)).toEqual(agentIds.toReversed())
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/__tests__/stores/company.test.ts` around lines 390 - 407, The
assertions use a.id only and therefore miss agents that fallback to name; update
both checks that currently call .map((a) => a.id) (the "reordered" and
"restored" expectations) to use the same fallback logic as agentIds: .map(a =>
a.id ?? a.name). This keeps the assertions aligned with the agentIds variable
and with the optimisticReorderAgents behavior; ensure the rollback expectation
still compares to agentIds.toReversed() but using the same fallback mapping.
web/src/pages/org/build-org-tree.ts (1)

23-30: ⚠️ Potential issue | 🟠 Major

Thread department currency through the org-chart node data.

DepartmentHealth now carries per-department currency, but this payload only preserves cost7d. web/src/pages/org/DepartmentGroupNode.tsx then forwards no currency to DepartmentStatsBar, and web/src/pages/org/DepartmentStatsBar.tsx falls back that prop to "EUR". Any non-EUR department will therefore render the wrong cost label in the org chart.

💱 Suggested change
 export interface DepartmentGroupData {
   departmentName: DepartmentName
   displayName: string
   healthPercent: number | null
   agentCount: number
   activeCount: number
   cost7d: number | null
+  currency: string | null
   isDropTarget?: boolean
   [key: string]: unknown
 }
       data: {
         departmentName: dept.name,
         displayName: dept.display_name ?? dept.name,
         healthPercent: health?.utilization_percent ?? null,
         agentCount: deptMembers.length,
         activeCount,
         cost7d: health?.department_cost_7d ?? null,
+        currency: health?.currency ?? null,
       } satisfies DepartmentGroupData,

Then pass data.currency ?? undefined from web/src/pages/org/DepartmentGroupNode.tsx into DepartmentStatsBar.

Also applies to: 105-112

🤖 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 23 - 30,
DepartmentGroupData currently only includes cost7d so the per-department
currency from DepartmentHealth is dropped, causing DepartmentStatsBar to default
to "EUR"; update the data flow to preserve and pass currency: add currency?:
string to the DepartmentGroupData shape (referenced in
web/src/pages/org/build-org-tree.ts), ensure DepartmentGroupNode
(web/src/pages/org/DepartmentGroupNode.tsx) reads data.currency (from
DepartmentHealth) and passes data.currency ?? undefined into the
DepartmentStatsBar component, and update DepartmentStatsBar prop usage
(web/src/pages/org/DepartmentStatsBar.tsx) to accept and use that currency prop
instead of falling back to "EUR".
🤖 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-edit/DepartmentsTab.test.tsx`:
- Around line 11-14: The test fixture now uses the renamed field
utilization_percent but the test only counts meter elements, so add an assertion
that the rendered percentage (e.g., "72%") appears (or that the specific meter
element for makeDepartmentHealth('product') has value 72) to ensure the new
field is actually used; update the DepartmentsTab.test.tsx assertions to check
for the visible "72%" (or query the meter value for the product department) and
also ensure the department_name lookup still targets the correct department
entry produced by makeDepartmentHealth.

In `@web/src/__tests__/utils/dashboard.test.ts`:
- Around line 187-190: The helper dh currently casts the name parameter to
DepartmentHealth['department_name'] which weakens fixture typing; change the
function signature to accept name: DepartmentHealth['department_name'] (i.e.
function dh(name: DepartmentHealth['department_name'], utilization: number,
agents = 1)) and remove the inline cast in the returned object so the
department_name field is strongly typed from the parameter; keep the rest of the
object shape the same.

In `@web/src/components/ui/dept-health-bar.tsx`:
- Line 42: The component prop name 'health' in DeptHealthBar should be renamed
to a domain-accurate name (e.g., utilizationPercent) to match the aria-label
wording; update the DeptHealthBar component signature, its props interface/type,
any defaultProps or destructuring that uses 'health', and all call sites that
pass the prop to use utilizationPercent instead (or add a short-lived alias
mapping from health => utilizationPercent to preserve backwards compatibility
while you update callers); also update the aria-label usage at the line with
aria-label={`${name} utilization: ${clamped != null ? `${clamped}%` :
'unavailable'}`} to read the new prop name.

In `@web/src/hooks/useAgentsData.ts`:
- Line 9: The WS refetch debounce value and logic duplicated by WS_DEBOUNCE_MS
in useAgentsData.ts (and the identical timeout/reset logic in
useAgentDetailData.ts) should be centralized: extract the numeric debounce
constant and any small helper debounce/reset function into a shared module
(e.g., export WS_DEBOUNCE_MS and a debounceReset helper) and import those
symbols into useAgentsData.ts and useAgentDetailData.ts, replacing the local
WS_DEBOUNCE_MS and duplicated timeout/reset logic so both hooks use the single
shared source of truth for debounce timing and behavior.

In `@web/src/pages/org-edit/AgentEditDrawer.tsx`:
- Around line 153-156: The JSX currently stringifies agent.model fields directly
causing “[object Object]” or an unwanted " / " when values are missing; update
AgentEditDrawer to first extract agent.model.provider and agent.model.model_id
into a modelParts array that only keeps values where typeof === 'string' and
value.length > 0, then conditionally render the <p> element only when
modelParts.length > 0 and join the parts with ' / ' (use modelParts.join(' / '))
so the separator appears only between real string parts.

In `@web/src/pages/org/DepartmentStatsBar.tsx`:
- Line 24: The conditional rendering currently only checks cost7d !== null which
still allows NaN/Infinity to reach formatCurrency; update the guard in
DepartmentStatsBar (the JSX that renders StatPill with label "Cost (7d)") to
only render when Number.isFinite(cost7d) (or equivalent finite-number check)
before calling formatCurrency so StatPill receives a valid numeric value.

In `@web/src/stores/budget.ts`:
- Around line 125-127: The map keys for agentNameMap/agentDeptMap currently use
agent.id ?? agent.name which can mismatch lookups by r.agent_id; normalize and
populate keys so lookups succeed regardless of which identifier is used. Change
the logic in the block that sets agentNameMap and agentDeptMap (where agentId is
computed) to: compute a canonicalKey = String(agent.id ?? agent.name) and set
maps under that key, and if agent.id exists also set the maps under
String(agent.id) and String(agent.name) (or vice‑versa) so lookups by r.agent_id
or by agent.name both resolve; ensure you use the same normalization
(String(...)) as used when reading r.agent_id in the budget aggregation code.

---

Outside diff comments:
In `@web/src/__tests__/stores/company.test.ts`:
- Around line 390-407: The assertions use a.id only and therefore miss agents
that fallback to name; update both checks that currently call .map((a) => a.id)
(the "reordered" and "restored" expectations) to use the same fallback logic as
agentIds: .map(a => a.id ?? a.name). This keeps the assertions aligned with the
agentIds variable and with the optimisticReorderAgents behavior; ensure the
rollback expectation still compares to agentIds.toReversed() but using the same
fallback mapping.

In `@web/src/hooks/useAgentDetailData.ts`:
- Around line 96-116: The socket handlers currently never get installed/removed
when agentName transitions because useWebSocket ignores later bindings changes;
fix by tying the socket lifecycle to agentName and clearing pending debounce on
name changes: pass enabled: Boolean(agentName) into useWebSocket({ bindings,
enabled: !!agentName }) so the hook sets up/tears down when agentName changes,
and add a useEffect that watches agentName and on change clears any pending
timeout on wsDebounceRef.current (and optionally resets agentNameRef.current) to
prevent fetchAgentDetail('') from firing; keep DETAIL_CHANNELS, bindings,
wsDebounceRef, useEffect, useWebSocket, fetchAgentDetail and agentNameRef
references to locate where to modify.

In `@web/src/pages/org-edit/AgentsTab.tsx`:
- Around line 168-177: Add a POST handler on the backend to implement the
/departments/{name}/reorder-agents endpoint: add a method (e.g., reorderAgents)
to DepartmentController that accepts a body { agent_ids: string[] }, validates
each entry is a valid agent ID (e.g., UUID format) and belongs to the given
department, rejects with 400 if any ID is missing/invalid (do not accept names
as IDs), and calls a service method (e.g.,
DepartmentService.reorderAgents(departmentName, agentIds)) to persist the new
order; ensure the controller returns appropriate success/error responses and
that DepartmentService updates the stored order for that department atomically.

In `@web/src/pages/org/build-org-tree.ts`:
- Around line 23-30: DepartmentGroupData currently only includes cost7d so the
per-department currency from DepartmentHealth is dropped, causing
DepartmentStatsBar to default to "EUR"; update the data flow to preserve and
pass currency: add currency?: string to the DepartmentGroupData shape
(referenced in web/src/pages/org/build-org-tree.ts), ensure DepartmentGroupNode
(web/src/pages/org/DepartmentGroupNode.tsx) reads data.currency (from
DepartmentHealth) and passes data.currency ?? undefined into the
DepartmentStatsBar component, and update DepartmentStatsBar prop usage
(web/src/pages/org/DepartmentStatsBar.tsx) to accept and use that currency prop
instead of falling back to "EUR".
🪄 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: 8f443f80-1987-4202-887a-693753dcb774

📥 Commits

Reviewing files that changed from the base of the PR and between 87bf8e6 and 7479977.

📒 Files selected for processing (52)
  • CLAUDE.md
  • docs/design/brand-and-ux.md
  • web/src/__tests__/components/ui/dept-health-bar.test.tsx
  • web/src/__tests__/helpers/factories.ts
  • web/src/__tests__/hooks/useAgentDetailData.test.ts
  • web/src/__tests__/hooks/useAgentsData.test.ts
  • web/src/__tests__/pages/dashboard/OrgHealthSection.test.tsx
  • web/src/__tests__/pages/org-edit/DepartmentsTab.test.tsx
  • web/src/__tests__/pages/org/DepartmentStatsBar.test.tsx
  • web/src/__tests__/pages/org/build-org-tree.test.ts
  • web/src/__tests__/stores/agents.test.ts
  • web/src/__tests__/stores/analytics.test.ts
  • web/src/__tests__/stores/budget.test.ts
  • web/src/__tests__/stores/company.test.ts
  • web/src/__tests__/utils/agents.property.test.ts
  • web/src/__tests__/utils/agents.test.ts
  • web/src/__tests__/utils/dashboard.property.test.ts
  • web/src/__tests__/utils/dashboard.test.ts
  • web/src/api/types.ts
  • web/src/components/ui/dept-health-bar.stories.tsx
  • web/src/components/ui/dept-health-bar.tsx
  • web/src/hooks/useAgentDetailData.ts
  • web/src/hooks/useAgentsData.ts
  • web/src/pages/AgentDetailPage.tsx
  • web/src/pages/DashboardPage.tsx
  • web/src/pages/agents/AgentGridView.stories.tsx
  • web/src/pages/agents/AgentGridView.tsx
  • web/src/pages/agents/AgentIdentityHeader.stories.tsx
  • web/src/pages/agents/AgentIdentityHeader.tsx
  • web/src/pages/dashboard/DashboardPage.stories.tsx
  • web/src/pages/dashboard/OrgHealthSection.stories.tsx
  • web/src/pages/dashboard/OrgHealthSection.tsx
  • web/src/pages/org-edit/AgentCreateDialog.stories.tsx
  • web/src/pages/org-edit/AgentEditDrawer.stories.tsx
  • web/src/pages/org-edit/AgentEditDrawer.tsx
  • web/src/pages/org-edit/AgentsTab.stories.tsx
  • web/src/pages/org-edit/AgentsTab.tsx
  • web/src/pages/org-edit/DepartmentEditDrawer.stories.tsx
  • web/src/pages/org-edit/DepartmentEditDrawer.tsx
  • web/src/pages/org-edit/DepartmentsTab.stories.tsx
  • web/src/pages/org-edit/DepartmentsTab.tsx
  • web/src/pages/org-edit/YamlEditorPanel.stories.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/build-org-tree.ts
  • web/src/pages/setup/ThemePreview.tsx
  • web/src/stores/budget.ts
  • web/src/stores/company.ts
  • web/src/utils/agents.ts
  • web/src/utils/dashboard.ts
💤 Files with no reviewable changes (1)
  • web/src/pages/DashboardPage.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 Web
  • GitHub Check: Build Sandbox
  • GitHub Check: Build Backend
  • GitHub Check: Dependency Review
  • GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (9)
web/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

web/src/**/*.{ts,tsx}: Web Dashboard: ALWAYS reuse existing components from web/src/components/ui/ before creating new ones. Reuse StatusBadge, MetricCard, Sparkline, SectionCard, AgentCard, DeptHealthBar, ProgressGauge, StatPill, Avatar, Button, Toast, Skeleton variants, EmptyState, ErrorBoundary, ConfirmDialog, CommandPalette, InlineEdit, AnimatedPresence, StaggerGroup, Drawer, InputField, SelectField, SliderField, ToggleField, TaskStatusIndicator, PriorityBadge, ProviderHealthBadge, TokenUsageBar, CodeMirrorEditor, SegmentedControl, ThemeToggle.
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 text-metric font-bold—use <MetricCard>. Do NOT render initials circles manually—use <Avatar>. Do NOT create complex (>8 line) JSX inside .map()—extract to a shared component.
Web design system enforcement: A PostToolUse hook (scripts/check_web_design_system.py) runs automatically on every Edit/Write to web/src/ files. It catches hardcoded hex colors, rgba values, font-family declarations, missing Storybook stories, duplicate patterns, and complex map blocks. Fix all violations before proceeding.
React 19 + shadcn/ui + Tailwind CSS 4 dashboard: Use React Router, Zustand stores, @tanstack/react-query, @xyflow/react, @dagrejs/dagre, d3-force, @dnd-kit, Recharts, Framer Motion, cmdk, js-yaml, Axios.

Files:

  • web/src/pages/org-edit/AgentEditDrawer.stories.tsx
  • web/src/__tests__/stores/agents.test.ts
  • web/src/__tests__/pages/org-edit/DepartmentsTab.test.tsx
  • web/src/__tests__/utils/agents.property.test.ts
  • web/src/__tests__/utils/agents.test.ts
  • web/src/__tests__/stores/budget.test.ts
  • web/src/pages/agents/AgentIdentityHeader.stories.tsx
  • web/src/pages/org/DepartmentGroupNode.tsx
  • web/src/pages/org-edit/AgentsTab.stories.tsx
  • web/src/stores/budget.ts
  • web/src/components/ui/dept-health-bar.tsx
  • web/src/pages/AgentDetailPage.tsx
  • web/src/__tests__/hooks/useAgentsData.test.ts
  • web/src/pages/org-edit/AgentEditDrawer.tsx
  • web/src/pages/org-edit/DepartmentEditDrawer.tsx
  • web/src/hooks/useAgentsData.ts
  • web/src/pages/org-edit/AgentCreateDialog.stories.tsx
  • web/src/pages/org-edit/YamlEditorPanel.stories.tsx
  • web/src/utils/dashboard.ts
  • web/src/pages/setup/ThemePreview.tsx
  • web/src/__tests__/components/ui/dept-health-bar.test.tsx
  • web/src/pages/agents/AgentGridView.stories.tsx
  • web/src/components/ui/dept-health-bar.stories.tsx
  • web/src/pages/agents/AgentIdentityHeader.tsx
  • web/src/pages/org/DepartmentGroupNode.stories.tsx
  • web/src/pages/org-edit/DepartmentsTab.tsx
  • web/src/pages/org-edit/DepartmentEditDrawer.stories.tsx
  • web/src/hooks/useAgentDetailData.ts
  • web/src/pages/org-edit/DepartmentsTab.stories.tsx
  • web/src/pages/agents/AgentGridView.tsx
  • web/src/pages/dashboard/DashboardPage.stories.tsx
  • web/src/__tests__/pages/dashboard/OrgHealthSection.test.tsx
  • web/src/stores/company.ts
  • web/src/__tests__/pages/org/DepartmentStatsBar.test.tsx
  • web/src/__tests__/utils/dashboard.test.ts
  • web/src/__tests__/hooks/useAgentDetailData.test.ts
  • web/src/pages/org-edit/AgentsTab.tsx
  • web/src/__tests__/utils/dashboard.property.test.ts
  • web/src/pages/org/DepartmentStatsBar.stories.tsx
  • web/src/utils/agents.ts
  • web/src/__tests__/stores/analytics.test.ts
  • web/src/__tests__/helpers/factories.ts
  • web/src/__tests__/stores/company.test.ts
  • web/src/pages/dashboard/OrgHealthSection.stories.tsx
  • web/src/__tests__/pages/org/build-org-tree.test.ts
  • web/src/pages/org/DepartmentStatsBar.tsx
  • web/src/pages/org/build-org-tree.ts
  • web/src/pages/dashboard/OrgHealthSection.tsx
  • web/src/api/types.ts
web/src/**/*.{ts,tsx,css}

📄 CodeRabbit inference engine (CLAUDE.md)

Design tokens: Colors use Tailwind semantic classes (text-foreground, bg-card, text-accent, etc.) or CSS variables (var(--so-accent)). NEVER hardcode hex values. Typography uses font-sans or font-mono. Spacing uses density-aware tokens or standard Tailwind. Shadows/borders use token variables.

Files:

  • web/src/pages/org-edit/AgentEditDrawer.stories.tsx
  • web/src/__tests__/stores/agents.test.ts
  • web/src/__tests__/pages/org-edit/DepartmentsTab.test.tsx
  • web/src/__tests__/utils/agents.property.test.ts
  • web/src/__tests__/utils/agents.test.ts
  • web/src/__tests__/stores/budget.test.ts
  • web/src/pages/agents/AgentIdentityHeader.stories.tsx
  • web/src/pages/org/DepartmentGroupNode.tsx
  • web/src/pages/org-edit/AgentsTab.stories.tsx
  • web/src/stores/budget.ts
  • web/src/components/ui/dept-health-bar.tsx
  • web/src/pages/AgentDetailPage.tsx
  • web/src/__tests__/hooks/useAgentsData.test.ts
  • web/src/pages/org-edit/AgentEditDrawer.tsx
  • web/src/pages/org-edit/DepartmentEditDrawer.tsx
  • web/src/hooks/useAgentsData.ts
  • web/src/pages/org-edit/AgentCreateDialog.stories.tsx
  • web/src/pages/org-edit/YamlEditorPanel.stories.tsx
  • web/src/utils/dashboard.ts
  • web/src/pages/setup/ThemePreview.tsx
  • web/src/__tests__/components/ui/dept-health-bar.test.tsx
  • web/src/pages/agents/AgentGridView.stories.tsx
  • web/src/components/ui/dept-health-bar.stories.tsx
  • web/src/pages/agents/AgentIdentityHeader.tsx
  • web/src/pages/org/DepartmentGroupNode.stories.tsx
  • web/src/pages/org-edit/DepartmentsTab.tsx
  • web/src/pages/org-edit/DepartmentEditDrawer.stories.tsx
  • web/src/hooks/useAgentDetailData.ts
  • web/src/pages/org-edit/DepartmentsTab.stories.tsx
  • web/src/pages/agents/AgentGridView.tsx
  • web/src/pages/dashboard/DashboardPage.stories.tsx
  • web/src/__tests__/pages/dashboard/OrgHealthSection.test.tsx
  • web/src/stores/company.ts
  • web/src/__tests__/pages/org/DepartmentStatsBar.test.tsx
  • web/src/__tests__/utils/dashboard.test.ts
  • web/src/__tests__/hooks/useAgentDetailData.test.ts
  • web/src/pages/org-edit/AgentsTab.tsx
  • web/src/__tests__/utils/dashboard.property.test.ts
  • web/src/pages/org/DepartmentStatsBar.stories.tsx
  • web/src/utils/agents.ts
  • web/src/__tests__/stores/analytics.test.ts
  • web/src/__tests__/helpers/factories.ts
  • web/src/__tests__/stores/company.test.ts
  • web/src/pages/dashboard/OrgHealthSection.stories.tsx
  • web/src/__tests__/pages/org/build-org-tree.test.ts
  • web/src/pages/org/DepartmentStatsBar.tsx
  • web/src/pages/org/build-org-tree.ts
  • web/src/pages/dashboard/OrgHealthSection.tsx
  • web/src/api/types.ts
**/*.{ts,tsx,json}

📄 CodeRabbit inference engine (CLAUDE.md)

TypeScript 6.0: Remove baseUrl (deprecated); paths entries are relative to tsconfig directory. esModuleInterop always true—cannot be set to false. types defaults to []—must explicitly list (e.g. 'types': ['vitest/globals']). DOM.Iterable merged into DOM. moduleResolution: 'classic' and 'node10' removed—use 'bundler' or 'nodenext'. strict defaults to true. noUncheckedSideEffectImports defaults to true.

Files:

  • web/src/pages/org-edit/AgentEditDrawer.stories.tsx
  • web/src/__tests__/stores/agents.test.ts
  • web/src/__tests__/pages/org-edit/DepartmentsTab.test.tsx
  • web/src/__tests__/utils/agents.property.test.ts
  • web/src/__tests__/utils/agents.test.ts
  • web/src/__tests__/stores/budget.test.ts
  • web/src/pages/agents/AgentIdentityHeader.stories.tsx
  • web/src/pages/org/DepartmentGroupNode.tsx
  • web/src/pages/org-edit/AgentsTab.stories.tsx
  • web/src/stores/budget.ts
  • web/src/components/ui/dept-health-bar.tsx
  • web/src/pages/AgentDetailPage.tsx
  • web/src/__tests__/hooks/useAgentsData.test.ts
  • web/src/pages/org-edit/AgentEditDrawer.tsx
  • web/src/pages/org-edit/DepartmentEditDrawer.tsx
  • web/src/hooks/useAgentsData.ts
  • web/src/pages/org-edit/AgentCreateDialog.stories.tsx
  • web/src/pages/org-edit/YamlEditorPanel.stories.tsx
  • web/src/utils/dashboard.ts
  • web/src/pages/setup/ThemePreview.tsx
  • web/src/__tests__/components/ui/dept-health-bar.test.tsx
  • web/src/pages/agents/AgentGridView.stories.tsx
  • web/src/components/ui/dept-health-bar.stories.tsx
  • web/src/pages/agents/AgentIdentityHeader.tsx
  • web/src/pages/org/DepartmentGroupNode.stories.tsx
  • web/src/pages/org-edit/DepartmentsTab.tsx
  • web/src/pages/org-edit/DepartmentEditDrawer.stories.tsx
  • web/src/hooks/useAgentDetailData.ts
  • web/src/pages/org-edit/DepartmentsTab.stories.tsx
  • web/src/pages/agents/AgentGridView.tsx
  • web/src/pages/dashboard/DashboardPage.stories.tsx
  • web/src/__tests__/pages/dashboard/OrgHealthSection.test.tsx
  • web/src/stores/company.ts
  • web/src/__tests__/pages/org/DepartmentStatsBar.test.tsx
  • web/src/__tests__/utils/dashboard.test.ts
  • web/src/__tests__/hooks/useAgentDetailData.test.ts
  • web/src/pages/org-edit/AgentsTab.tsx
  • web/src/__tests__/utils/dashboard.property.test.ts
  • web/src/pages/org/DepartmentStatsBar.stories.tsx
  • web/src/utils/agents.ts
  • web/src/__tests__/stores/analytics.test.ts
  • web/src/__tests__/helpers/factories.ts
  • web/src/__tests__/stores/company.test.ts
  • web/src/pages/dashboard/OrgHealthSection.stories.tsx
  • web/src/__tests__/pages/org/build-org-tree.test.ts
  • web/src/pages/org/DepartmentStatsBar.tsx
  • web/src/pages/org/build-org-tree.ts
  • web/src/pages/dashboard/OrgHealthSection.tsx
  • web/src/api/types.ts
web/**/*.stories.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Storybook 10: ESM-only—no CJS support. Packages like @storybook/addon-essentials, @storybook/addon-interactions, @storybook/test, @storybook/blocks no longer published. @storybook/addon-docs is separate. Import from storybook/test (not @storybook/test), storybook/actions. Use defineMain from @storybook/react-vite/node and definePreview from @storybook/react-vite. Backgrounds API: use parameters.backgrounds.options (object) + initialGlobals.backgrounds.value. a11y testing: use parameters.a11y.test: 'error' | 'todo' | 'off'. Minimum versions: Node 20.19+, Vite 5+, Vitest 3+, TypeScript 4.9+.

Files:

  • web/src/pages/org-edit/AgentEditDrawer.stories.tsx
  • web/src/pages/agents/AgentIdentityHeader.stories.tsx
  • web/src/pages/org-edit/AgentsTab.stories.tsx
  • web/src/pages/org-edit/AgentCreateDialog.stories.tsx
  • web/src/pages/org-edit/YamlEditorPanel.stories.tsx
  • web/src/pages/agents/AgentGridView.stories.tsx
  • web/src/components/ui/dept-health-bar.stories.tsx
  • web/src/pages/org/DepartmentGroupNode.stories.tsx
  • web/src/pages/org-edit/DepartmentEditDrawer.stories.tsx
  • web/src/pages/org-edit/DepartmentsTab.stories.tsx
  • web/src/pages/dashboard/DashboardPage.stories.tsx
  • web/src/pages/org/DepartmentStatsBar.stories.tsx
  • web/src/pages/dashboard/OrgHealthSection.stories.tsx
**/*.{py,ts,tsx,go}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{py,ts,tsx,go}: Lint & format: Python via ruff (uv run ruff check + uv run ruff format). TypeScript web via ESLint (zero warnings enforced: npm --prefix web run lint). Go CLI via golangci-lint and go vet. All enforced in pre-commit hooks.
Type checking: Python via mypy strict mode (uv run mypy src/ tests/). TypeScript via npm --prefix web run type-check. Go via go -C cli vet ./....

Files:

  • web/src/pages/org-edit/AgentEditDrawer.stories.tsx
  • web/src/__tests__/stores/agents.test.ts
  • web/src/__tests__/pages/org-edit/DepartmentsTab.test.tsx
  • web/src/__tests__/utils/agents.property.test.ts
  • web/src/__tests__/utils/agents.test.ts
  • web/src/__tests__/stores/budget.test.ts
  • web/src/pages/agents/AgentIdentityHeader.stories.tsx
  • web/src/pages/org/DepartmentGroupNode.tsx
  • web/src/pages/org-edit/AgentsTab.stories.tsx
  • web/src/stores/budget.ts
  • web/src/components/ui/dept-health-bar.tsx
  • web/src/pages/AgentDetailPage.tsx
  • web/src/__tests__/hooks/useAgentsData.test.ts
  • web/src/pages/org-edit/AgentEditDrawer.tsx
  • web/src/pages/org-edit/DepartmentEditDrawer.tsx
  • web/src/hooks/useAgentsData.ts
  • web/src/pages/org-edit/AgentCreateDialog.stories.tsx
  • web/src/pages/org-edit/YamlEditorPanel.stories.tsx
  • web/src/utils/dashboard.ts
  • web/src/pages/setup/ThemePreview.tsx
  • web/src/__tests__/components/ui/dept-health-bar.test.tsx
  • web/src/pages/agents/AgentGridView.stories.tsx
  • web/src/components/ui/dept-health-bar.stories.tsx
  • web/src/pages/agents/AgentIdentityHeader.tsx
  • web/src/pages/org/DepartmentGroupNode.stories.tsx
  • web/src/pages/org-edit/DepartmentsTab.tsx
  • web/src/pages/org-edit/DepartmentEditDrawer.stories.tsx
  • web/src/hooks/useAgentDetailData.ts
  • web/src/pages/org-edit/DepartmentsTab.stories.tsx
  • web/src/pages/agents/AgentGridView.tsx
  • web/src/pages/dashboard/DashboardPage.stories.tsx
  • web/src/__tests__/pages/dashboard/OrgHealthSection.test.tsx
  • web/src/stores/company.ts
  • web/src/__tests__/pages/org/DepartmentStatsBar.test.tsx
  • web/src/__tests__/utils/dashboard.test.ts
  • web/src/__tests__/hooks/useAgentDetailData.test.ts
  • web/src/pages/org-edit/AgentsTab.tsx
  • web/src/__tests__/utils/dashboard.property.test.ts
  • web/src/pages/org/DepartmentStatsBar.stories.tsx
  • web/src/utils/agents.ts
  • web/src/__tests__/stores/analytics.test.ts
  • web/src/__tests__/helpers/factories.ts
  • web/src/__tests__/stores/company.test.ts
  • web/src/pages/dashboard/OrgHealthSection.stories.tsx
  • web/src/__tests__/pages/org/build-org-tree.test.ts
  • web/src/pages/org/DepartmentStatsBar.tsx
  • web/src/pages/org/build-org-tree.ts
  • web/src/pages/dashboard/OrgHealthSection.tsx
  • web/src/api/types.ts
web/src/pages/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Web dashboard pages: Lazy-loaded page components (one per route). Page-scoped sub-components in pages/<page-name>/ subdirs. Feature dirs added as pages are built. Stores for auth, WebSocket, toast, analytics, setup wizard, company, agents, budget, tasks, settings, providers, theme.

Files:

  • web/src/pages/org-edit/AgentEditDrawer.stories.tsx
  • web/src/pages/agents/AgentIdentityHeader.stories.tsx
  • web/src/pages/org/DepartmentGroupNode.tsx
  • web/src/pages/org-edit/AgentsTab.stories.tsx
  • web/src/pages/AgentDetailPage.tsx
  • web/src/pages/org-edit/AgentEditDrawer.tsx
  • web/src/pages/org-edit/DepartmentEditDrawer.tsx
  • web/src/pages/org-edit/AgentCreateDialog.stories.tsx
  • web/src/pages/org-edit/YamlEditorPanel.stories.tsx
  • web/src/pages/setup/ThemePreview.tsx
  • web/src/pages/agents/AgentGridView.stories.tsx
  • web/src/pages/agents/AgentIdentityHeader.tsx
  • web/src/pages/org/DepartmentGroupNode.stories.tsx
  • web/src/pages/org-edit/DepartmentsTab.tsx
  • web/src/pages/org-edit/DepartmentEditDrawer.stories.tsx
  • web/src/pages/org-edit/DepartmentsTab.stories.tsx
  • web/src/pages/agents/AgentGridView.tsx
  • web/src/pages/dashboard/DashboardPage.stories.tsx
  • web/src/pages/org-edit/AgentsTab.tsx
  • web/src/pages/org/DepartmentStatsBar.stories.tsx
  • web/src/pages/dashboard/OrgHealthSection.stories.tsx
  • web/src/pages/org/DepartmentStatsBar.tsx
  • web/src/pages/org/build-org-tree.ts
  • web/src/pages/dashboard/OrgHealthSection.tsx
web/src/components/ui/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Web components: Place new shared components in web/src/components/ui/ with kebab-case filenames. Create .stories.tsx with all states. Export props as TypeScript interface. Use design tokens exclusively—no hardcoded colors, fonts, or spacing. Import cn from @/lib/utils for conditional class merging.

Files:

  • web/src/components/ui/dept-health-bar.tsx
  • web/src/components/ui/dept-health-bar.stories.tsx
docs/design/*.md

📄 CodeRabbit inference engine (CLAUDE.md)

When approved deviations occur, update the relevant docs/design/ page to reflect the new reality.

Files:

  • docs/design/brand-and-ux.md
docs/**/*.md

📄 CodeRabbit inference engine (CLAUDE.md)

Documentation: docs/ (Markdown, built with Zensical, config: mkdocs.yml). Design spec in docs/design/ (11 pages), architecture in docs/architecture/, roadmap in docs/roadmap/. REST API reference auto-generated by scripts/export_openapi.py. Library reference auto-generated via mkdocstrings + Griffe. Landing page in site/ (Astro).

Files:

  • docs/design/brand-and-ux.md
🧠 Learnings (12)
📓 Common learnings
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-29T11:41:44.483Z
Learning: Applies to web/src/**/*.{ts,tsx} : Web Dashboard: ALWAYS reuse existing components from `web/src/components/ui/` before creating new ones. Reuse StatusBadge, MetricCard, Sparkline, SectionCard, AgentCard, DeptHealthBar, ProgressGauge, StatPill, Avatar, Button, Toast, Skeleton variants, EmptyState, ErrorBoundary, ConfirmDialog, CommandPalette, InlineEdit, AnimatedPresence, StaggerGroup, Drawer, InputField, SelectField, SliderField, ToggleField, TaskStatusIndicator, PriorityBadge, ProviderHealthBadge, TokenUsageBar, CodeMirrorEditor, SegmentedControl, ThemeToggle.
📚 Learning: 2026-03-29T11:41:44.483Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-29T11:41:44.483Z
Learning: Applies to web/**/*.stories.{ts,tsx} : Storybook 10: ESM-only—no CJS support. Packages like `storybook/addon-essentials`, `storybook/addon-interactions`, `storybook/test`, `storybook/blocks` no longer published. `storybook/addon-docs` is separate. Import from `storybook/test` (not `storybook/test`), `storybook/actions`. Use `defineMain` from `storybook/react-vite/node` and `definePreview` from `storybook/react-vite`. Backgrounds API: use `parameters.backgrounds.options` (object) + `initialGlobals.backgrounds.value`. a11y testing: use `parameters.a11y.test: 'error' | 'todo' | 'off'`. Minimum versions: Node 20.19+, Vite 5+, Vitest 3+, TypeScript 4.9+.

Applied to files:

  • web/src/pages/org-edit/AgentEditDrawer.stories.tsx
  • web/src/pages/org-edit/AgentsTab.stories.tsx
  • web/src/pages/org-edit/AgentCreateDialog.stories.tsx
  • web/src/pages/org-edit/YamlEditorPanel.stories.tsx
  • web/src/pages/agents/AgentGridView.stories.tsx
  • web/src/components/ui/dept-health-bar.stories.tsx
  • web/src/pages/org/DepartmentGroupNode.stories.tsx
  • web/src/pages/org-edit/DepartmentEditDrawer.stories.tsx
  • web/src/pages/org-edit/DepartmentsTab.stories.tsx
  • web/src/pages/org/DepartmentStatsBar.stories.tsx
📚 Learning: 2026-03-29T11:41:44.483Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-29T11:41:44.483Z
Learning: Applies to web/src/**/*.{ts,tsx} : Web Dashboard: ALWAYS reuse existing components from `web/src/components/ui/` before creating new ones. Reuse StatusBadge, MetricCard, Sparkline, SectionCard, AgentCard, DeptHealthBar, ProgressGauge, StatPill, Avatar, Button, Toast, Skeleton variants, EmptyState, ErrorBoundary, ConfirmDialog, CommandPalette, InlineEdit, AnimatedPresence, StaggerGroup, Drawer, InputField, SelectField, SliderField, ToggleField, TaskStatusIndicator, PriorityBadge, ProviderHealthBadge, TokenUsageBar, CodeMirrorEditor, SegmentedControl, ThemeToggle.

Applied to files:

  • CLAUDE.md
  • web/src/components/ui/dept-health-bar.tsx
  • web/src/pages/AgentDetailPage.tsx
  • web/src/pages/org-edit/AgentEditDrawer.tsx
  • web/src/pages/org-edit/DepartmentEditDrawer.tsx
  • web/src/utils/dashboard.ts
  • web/src/pages/setup/ThemePreview.tsx
  • web/src/components/ui/dept-health-bar.stories.tsx
  • web/src/pages/org-edit/DepartmentsTab.tsx
  • web/src/pages/dashboard/DashboardPage.stories.tsx
  • web/src/__tests__/pages/dashboard/OrgHealthSection.test.tsx
  • web/src/__tests__/utils/dashboard.test.ts
  • web/src/pages/org-edit/AgentsTab.tsx
  • docs/design/brand-and-ux.md
  • web/src/pages/dashboard/OrgHealthSection.stories.tsx
  • web/src/pages/dashboard/OrgHealthSection.tsx
📚 Learning: 2026-03-29T11:41:44.483Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-29T11:41:44.483Z
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 `text-metric font-bold`—use `<MetricCard>`. Do NOT render initials circles manually—use `<Avatar>`. Do NOT create complex (>8 line) JSX inside `.map()`—extract to a shared component.

Applied to files:

  • CLAUDE.md
  • web/src/components/ui/dept-health-bar.tsx
  • web/src/pages/AgentDetailPage.tsx
  • web/src/pages/org-edit/DepartmentEditDrawer.tsx
  • web/src/pages/setup/ThemePreview.tsx
  • web/src/__tests__/components/ui/dept-health-bar.test.tsx
  • web/src/components/ui/dept-health-bar.stories.tsx
  • web/src/pages/agents/AgentIdentityHeader.tsx
  • web/src/pages/org-edit/DepartmentsTab.tsx
  • web/src/pages/agents/AgentGridView.tsx
  • web/src/__tests__/pages/org/DepartmentStatsBar.test.tsx
  • web/src/pages/org-edit/AgentsTab.tsx
  • docs/design/brand-and-ux.md
  • web/src/pages/dashboard/OrgHealthSection.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:

  • CLAUDE.md
  • docs/design/brand-and-ux.md
📚 Learning: 2026-03-29T11:41:44.483Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-29T11:41:44.483Z
Learning: Applies to web/src/components/ui/**/*.{ts,tsx} : Web components: Place new shared components in `web/src/components/ui/` with kebab-case filenames. Create `.stories.tsx` with all states. Export props as TypeScript interface. Use design tokens exclusively—no hardcoded colors, fonts, or spacing. Import `cn` from `@/lib/utils` for conditional class merging.

Applied to files:

  • CLAUDE.md
  • web/src/__tests__/components/ui/dept-health-bar.test.tsx
  • web/src/components/ui/dept-health-bar.stories.tsx
  • web/src/pages/org-edit/DepartmentEditDrawer.stories.tsx
  • web/src/pages/org-edit/DepartmentsTab.stories.tsx
  • web/src/pages/org/DepartmentStatsBar.stories.tsx
📚 Learning: 2026-03-29T11:41:44.483Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-29T11:41:44.483Z
Learning: Applies to web/src/**/*.{ts,tsx} : React 19 + shadcn/ui + Tailwind CSS 4 dashboard: Use React Router, Zustand stores, tanstack/react-query, xyflow/react, dagrejs/dagre, d3-force, dnd-kit, Recharts, Framer Motion, cmdk, js-yaml, Axios.

Applied to files:

  • CLAUDE.md
  • web/src/pages/org/DepartmentGroupNode.tsx
  • web/src/pages/org-edit/DepartmentEditDrawer.tsx
  • web/src/hooks/useAgentsData.ts
  • web/src/pages/org-edit/DepartmentsTab.tsx
  • web/src/hooks/useAgentDetailData.ts
  • web/src/pages/dashboard/DashboardPage.stories.tsx
  • web/src/pages/org-edit/AgentsTab.tsx
📚 Learning: 2026-03-29T11:41:44.483Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-29T11:41:44.483Z
Learning: Applies to web/src/pages/**/*.{ts,tsx} : Web dashboard pages: Lazy-loaded page components (one per route). Page-scoped sub-components in `pages/<page-name>/` subdirs. Feature dirs added as pages are built. Stores for auth, WebSocket, toast, analytics, setup wizard, company, agents, budget, tasks, settings, providers, theme.

Applied to files:

  • CLAUDE.md
  • web/src/pages/dashboard/DashboardPage.stories.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__/components/ui/dept-health-bar.test.tsx
  • web/src/__tests__/pages/dashboard/OrgHealthSection.test.tsx
  • web/src/__tests__/pages/org/DepartmentStatsBar.test.tsx
  • web/src/__tests__/utils/dashboard.test.ts
  • web/src/__tests__/utils/dashboard.property.test.ts
📚 Learning: 2026-03-29T11:41:44.483Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-29T11:41:44.483Z
Learning: Applies to web/src/**/*.{ts,tsx,css} : Design tokens: Colors use Tailwind semantic classes (`text-foreground`, `bg-card`, `text-accent`, etc.) or CSS variables (`var(--so-accent)`). NEVER hardcode hex values. Typography uses `font-sans` or `font-mono`. Spacing uses density-aware tokens or standard Tailwind. Shadows/borders use token variables.

Applied to files:

  • docs/design/brand-and-ux.md
📚 Learning: 2026-03-29T11:41:44.483Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-29T11:41:44.483Z
Learning: Applies to **/*.{ts,tsx,json} : TypeScript 6.0: Remove `baseUrl` (deprecated); `paths` entries are relative to tsconfig directory. `esModuleInterop` always true—cannot be set to `false`. `types` defaults to `[]`—must explicitly list (e.g. `'types': ['vitest/globals']`). `DOM.Iterable` merged into `DOM`. `moduleResolution: 'classic'` and `'node10'` removed—use `'bundler'` or `'nodenext'`. `strict` defaults to `true`. `noUncheckedSideEffectImports` defaults to `true`.

Applied to files:

  • web/src/api/types.ts
📚 Learning: 2026-03-29T11:41:44.483Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-29T11:41:44.483Z
Learning: Applies to src/synthorg/hr/**/*.py : HR: Hiring, firing, onboarding, agent registry, performance tracking, activity timeline, career history, promotion/demotion.

Applied to files:

  • web/src/api/types.ts
🔇 Additional comments (41)
CLAUDE.md (1)

246-246: Documentation update is consistent with current DeptHealthBar API.

This line now correctly reflects the component’s utilization semantics and current prop surface (health?, agentCount, no taskCount).

web/src/pages/agents/AgentIdentityHeader.stories.tsx (1)

23-23: Fixture update matches the new AgentConfig contract.

Adding authority: {} here keeps story args valid with the required field and avoids type/runtime drift in stories.

web/src/pages/setup/ThemePreview.tsx (1)

175-175: Callsite is correctly aligned with the updated DeptHealthBar API.

Good update removing the obsolete prop and keeping the preview in sync.

web/src/components/ui/dept-health-bar.stories.tsx (1)

17-17: Stories are consistently updated to the new prop contract.

All variants now correctly omit the removed prop and stay aligned with DeptHealthBar’s current API.

Also applies to: 21-21, 25-25, 29-29, 33-33, 37-37, 41-41, 44-47

web/src/__tests__/components/ui/dept-health-bar.test.tsx (1)

31-31: Test inputs are correctly synced with the component API changes.

These updates keep existing behavioral coverage intact while removing the obsolete prop usage.

Also applies to: 37-37, 49-49, 55-55, 63-63

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

74-74: arbAgent now matches the updated AgentConfig shape.

Adding authority here keeps property tests type-safe and representative.

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

134-134: Mock payload update is correct for the new agent schema.

Including authority keeps the budget-store fixture aligned with the current response shape.

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

53-53: Shared test fixture is correctly updated.

Adding authority in makeAgent keeps all dependent store tests aligned with the current type contract.

web/src/pages/org-edit/AgentEditDrawer.stories.tsx (1)

22-22: Fixture update matches the new AgentConfig contract.
authority: {} is correctly added in the story mock.

web/src/pages/org-edit/DepartmentEditDrawer.tsx (1)

88-88: Prop rename is correctly wired to the new health schema.
Using utilization_percent here is consistent with the updated DepartmentHealth model.

web/src/pages/org-edit/AgentsTab.stories.tsx (1)

23-23: Story fixtures are consistently aligned with the updated agent type.
Good update adding authority on each mock agent entry.

Also applies to: 44-44, 65-65

web/src/pages/agents/AgentIdentityHeader.tsx (1)

15-15: Null-safe handling is correct for optional runtime fields.
Defaulting missing status and guarding hiring_date rendering both look solid.

Also applies to: 39-46

web/src/utils/dashboard.ts (1)

99-99: computeOrgHealth migration is correctly implemented.
Validation, warning payload, and aggregation now consistently use utilization_percent/department_name.

Also applies to: 102-103, 107-107

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

42-42: DepartmentStatsBar prop update is correctly applied.
Passing cost7d here matches the updated stats-bar interface.

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

54-54: Test updates correctly cover the new agent schema and status fallback behavior.
Good addition of authority in the factory and explicit undefined-status filtering coverage.

Also applies to: 203-207

web/src/pages/AgentDetailPage.tsx (1)

74-74: Good runtime narrowing for tools.allowed.

This keeps ToolBadges insulated from the new Record<string, unknown> shape and safely drops malformed entries.

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

55-55: Story args match the renamed department stats field.

Switching these fixtures to cost7d keeps the stories aligned with DepartmentGroupData and DepartmentStatsBar, so they should keep catching prop drift after the schema rename.

Also applies to: 68-68, 81-81, 94-94

web/src/pages/org-edit/YamlEditorPanel.stories.tsx (1)

28-28: The story fixture stays in sync with required AgentConfig.authority.

Good update—this prevents the panel story from drifting away from the runtime schema.

web/src/pages/org-edit/DepartmentsTab.tsx (1)

80-80: The department-health rename is wired through consistently.

Using department_name for the lookup and utilization_percent for DeptHealthBar matches the backend model cleanly.

Also applies to: 114-114

web/src/pages/org-edit/AgentCreateDialog.stories.tsx (1)

22-22: The stub agent matches the updated schema.

Adding authority here keeps the create-dialog story aligned with the required AgentConfig shape.

web/src/pages/agents/AgentGridView.tsx (1)

28-29: Optional agent fields are handled cleanly here.

Defaulting a missing status, skipping formatRelativeTime when hiring_date is absent, and falling back to agent.name for the key make the grid resilient to partial agent payloads.

Also applies to: 55-55

web/src/pages/org-edit/AgentEditDrawer.tsx (1)

56-56: The optional status and hiring_date paths are handled well.

These fallbacks keep both the read-only header and the edit controls stable when older payloads omit those fields.

Also applies to: 69-69, 115-116, 148-148

web/src/pages/dashboard/DashboardPage.stories.tsx (1)

55-60: LGTM!

The mockDepartments fixture correctly implements the new DepartmentHealth schema with all required fields (department_name, agent_count, active_agent_count, currency, avg_performance_score, department_cost_7d, cost_trend, collaboration_score, utilization_percent). The nullable collaboration_score: null for operations is valid per the interface definition.

web/src/pages/agents/AgentGridView.stories.tsx (1)

33-33: LGTM!

The authority: {} field is correctly added to align with the updated AgentConfig schema that now requires authority. The removal of the skills default (no longer present) is consistent with the type changes.

web/src/pages/org-edit/AgentsTab.tsx (1)

50-50: LGTM on UI-local fallbacks.

Using agent.id ?? agent.name for sortable IDs and agent.status ?? 'active' for runtime status are appropriate fallbacks for UI rendering and local drag-and-drop behavior. These ensure the component doesn't break when optional fields are absent.

Also applies to: 73-73

web/src/pages/org-edit/DepartmentEditDrawer.stories.tsx (1)

14-24: LGTM!

The mockHealth fixture correctly implements all fields from the updated DepartmentHealth interface as defined in web/src/api/types.ts:558-572. The a11y testing configuration (test: 'error') is properly set per Storybook 10 standards.

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

23-45: LGTM!

The stories correctly use the new cost7d prop replacing taskCount and costUsd. The test coverage includes relevant edge cases: normal value, null, and zero. This aligns with the component's actual usage in DepartmentGroupNode.tsx.

web/src/pages/org-edit/DepartmentsTab.stories.tsx (2)

25-25: LGTM!

The authority: {} field is correctly added to the agent config to match the updated AgentConfig schema.


36-39: LGTM!

The mockHealths fixture correctly implements the new DepartmentHealth schema. The product department appropriately has null for avg_performance_score and collaboration_score since it has no agents (agent_count: 0).

web/src/utils/agents.ts (3)

71-73: LGTM!

Treating undefined status as 'active' in the filter is a sensible default that aligns with the PR objective of making status optional in AgentConfig.


106-116: LGTM on status sorting fallback.

The a.status ?? 'active' fallback for status sorting is consistent with the filter logic. The generic field fallback to '' handles missing fields gracefully for string comparisons.


249-267: LGTM!

Typing ACTIVITY_ICON_MAP as Partial<Record<ActivityEventType, LucideIcon>> correctly expresses that not all event types have dedicated icons. The cast in getActivityEventIcon is safe because the fallback ?? FALLBACK_ICON handles missing entries.

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

105-115: LGTM!

The arbDeptHealth generator correctly produces values matching the updated DepartmentHealth interface. The use of fc.option(..., { nil: null }) for nullable fields (avg_performance_score, collaboration_score) and constrained floats for utilization_percent ensures valid test data generation.

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

284-320: Consistent fallback identity handling in optimistic reorder/rollback

Good update: using a.id ?? a.name consistently in both forward reorder and rollback paths avoids dropping agents when id is absent.

web/src/__tests__/utils/dashboard.test.ts (1)

207-228: Org health tests are correctly aligned to utilization_percent

Coverage for rounding plus non-finite filtering (NaN/Infinity) is solid and matches the updated aggregation behavior.

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

7-34: Tests now correctly match the DepartmentStatsBar API

The updated assertions for cost7d, Cost (7d), and default EUR behavior are consistent with the component changes.

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

11-57: Fixture shape and currency assertions are correctly migrated

The updated department fixture fields and per-department currency checks match the new DepartmentHealth contract and rendering path.

web/src/pages/dashboard/OrgHealthSection.stories.tsx (1)

7-15: Story fixture migration is clean and consistent

makeDepts now emits the correct backend-aligned DepartmentHealth fields, which keeps stories in sync with runtime types.

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

46-55: Analytics store mocks/assertions are correctly aligned to utilization_percent

The migrated health fixtures and assertion updates are consistent with the new type contract and org-health derivation flow.

Also applies to: 142-157, 204-211

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

53-61: Department health test fixtures are correctly updated

The fixture now matches the backend-aligned DepartmentHealth shape, and the assertion switch to department_name is correct.

Also applies to: 158-158

web/src/pages/dashboard/OrgHealthSection.tsx (1)

15-29: Nice reuse of the shared dashboard primitives.

Extracting DepartmentRow keeps the .map() block small, and the section continues to compose SectionCard, DeptHealthBar, ProgressGauge, and EmptyState instead of rebuilding that pattern inline.

As per coding guidelines, "Web Dashboard: ALWAYS reuse existing components from web/src/components/ui/ before creating new ones." and "Do NOT create complex (>8 line) JSX inside .map()—extract to a shared component."

Also applies to: 32-53

? { role: 'meter', 'aria-valuenow': clamped, 'aria-valuemin': 0, 'aria-valuemax': 100 }
: {})}
aria-label={`${name} health: ${clamped != null ? `${clamped}%` : 'unavailable'}`}
aria-label={`${name} utilization: ${clamped != null ? `${clamped}%` : 'unavailable'}`}
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

Consider aligning prop naming with utilization terminology.

The aria label now correctly uses “utilization,” but the public prop is still health. A follow-up rename (e.g., utilizationPercent) would reduce domain ambiguity for future consumers.

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

In `@web/src/components/ui/dept-health-bar.tsx` at line 42, The component prop
name 'health' in DeptHealthBar should be renamed to a domain-accurate name
(e.g., utilizationPercent) to match the aria-label wording; update the
DeptHealthBar component signature, its props interface/type, any defaultProps or
destructuring that uses 'health', and all call sites that pass the prop to use
utilizationPercent instead (or add a short-lived alias mapping from health =>
utilizationPercent to preserve backwards compatibility while you update
callers); also update the aria-label usage at the line with aria-label={`${name}
utilization: ${clamped != null ? `${clamped}%` : 'unavailable'}`} to read the
new prop name.

import type { AgentConfig, WsChannel } from '@/api/types'

const AGENTS_POLL_INTERVAL = 30_000
const WS_DEBOUNCE_MS = 300
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

Centralize the WS refetch debounce policy.

This hook now duplicates the same 300ms constant and timeout/reset logic that was added to web/src/hooks/useAgentDetailData.ts. The next tuning change will require touching both hooks and both debounce test suites. A tiny shared helper/constant would keep list/detail behavior from drifting.

Also applies to: 53-67

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

In `@web/src/hooks/useAgentsData.ts` at line 9, The WS refetch debounce value and
logic duplicated by WS_DEBOUNCE_MS in useAgentsData.ts (and the identical
timeout/reset logic in useAgentDetailData.ts) should be centralized: extract the
numeric debounce constant and any small helper debounce/reset function into a
shared module (e.g., export WS_DEBOUNCE_MS and a debounceReset helper) and
import those symbols into useAgentsData.ts and useAgentDetailData.ts, replacing
the local WS_DEBOUNCE_MS and duplicated timeout/reset logic so both hooks use
the single shared source of truth for debounce timing and behavior.

@Aureliolo Aureliolo temporarily deployed to cloudflare-preview March 29, 2026 20:49 — with GitHub Actions Inactive
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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
web/src/hooks/useAgentDetailData.ts (1)

110-126: ⚠️ Potential issue | 🟠 Major

WebSocket binding lifecycle is broken when agentName changes.

At Line [123], bindings changes with agentName, but useWebSocket wires handlers from mount-time bindings only. This can miss WS setup on '' -> 'alice' transitions and can keep old handlers active when agentName becomes empty, leading to fetchAgentDetail('') from Line [118].

🔧 Suggested fix
-  const bindings: ChannelBinding[] = useMemo(
-    () =>
-      agentName
-        ? DETAIL_CHANNELS.map((channel) => ({
-            channel,
-            handler: () => {
-              if (wsDebounceRef.current) clearTimeout(wsDebounceRef.current)
-              wsDebounceRef.current = setTimeout(() => {
-                useAgentsStore.getState().fetchAgentDetail(agentNameRef.current)
-              }, WS_DEBOUNCE_MS)
-            },
-          }))
-        : EMPTY_BINDINGS,
-    [agentName],
-  )
-
-  const { connected: wsConnected, setupError: wsSetupError } = useWebSocket({ bindings })
+  const bindings: ChannelBinding[] = useMemo(
+    () =>
+      DETAIL_CHANNELS.map((channel) => ({
+        channel,
+        handler: () => {
+          const currentName = agentNameRef.current
+          if (!currentName) return
+          if (wsDebounceRef.current) clearTimeout(wsDebounceRef.current)
+          wsDebounceRef.current = setTimeout(() => {
+            useAgentsStore.getState().fetchAgentDetail(currentName)
+          }, WS_DEBOUNCE_MS)
+        },
+      })),
+    [],
+  )
+
+  const { connected: wsConnected, setupError: wsSetupError } = useWebSocket({
+    bindings,
+    enabled: Boolean(agentName),
+  })
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/hooks/useAgentDetailData.ts` around lines 110 - 126, The WebSocket
bindings capture agentName at creation and cause stale/no-op behavior on
transitions; fix by making the handler read the live ref and guard empty names
instead of closing over agentName: in useAgentDetailData update the binding
factory (used to build bindings passed to useWebSocket) so each handler does
const name = agentNameRef.current; if (!name) return; then perform the debounce
and call useAgentsStore.getState().fetchAgentDetail(name) (still using
wsDebounceRef and WS_DEBOUNCE_MS); keep DETAIL_CHANNELS and bindings structure
but ensure handlers never close over the outer agentName value so handlers
remain valid across agentName changes and won't call fetchAgentDetail('').
🤖 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__/hooks/useAgentDetailData.test.ts`:
- Around line 179-259: Add tests that exercise agentName prop transitions by
rendering useAgentDetailData with '' then rerendering to 'alice' and vice versa
to verify WebSocket handler setup/teardown; specifically, in the WebSocket
debounce suite add two cases: one that calls renderHook(() =>
useAgentDetailData('')) then rerender('alice'), fetches the new bindings from
vi.mocked(useWebSocket).mock.calls[0][0].bindings, triggers the handler(s),
advances timers and asserts mockFetchAgentDetail was called with 'alice'; and a
reverse case that starts with 'alice', rerenders to '' and asserts the previous
handlers were cleaned up (trigger handler after rerender/unmount and advance
timers to confirm mockFetchAgentDetail is not called). Ensure you reuse
setupHandler pattern (useWebSocket, wsHandler/agentsHandler/tasksHandler), clear
mockFetchAgentDetail between steps, and call
vi.useFakeTimers()/vi.useRealTimers() as in existing tests.

In `@web/src/__tests__/pages/org/build-org-tree.test.ts`:
- Around line 337-348: The test currently masks the optional id by using
"undefined as unknown as string"; instead update the fixture and test to
preserve the optional id typing: change makeAgent to accept id?: string
(optional) and in this test call makeAgent({ id: undefined, name: 'NoIdAgent',
... }) or simply omit the id field so the helper passes undefined naturally;
keep buildOrgTree usage unchanged and assert on the node id/data as before.

In `@web/src/__tests__/utils/agents.test.ts`:
- Around line 219-229: Update the test "treats agent with undefined status as
active for sorting" to include an explicit onboarding case so undefined isn't
accidentally treated as onboarding; add makeAgent({ name: 'Onboarding Agent',
status: 'onboarding' }) to the withUndefined array and then assert that
names.indexOf('No Status') is less than names.indexOf('Onboarding Agent') (and
keep/assert that it's also less than names.indexOf('Terminated Agent') if
desired) to ensure undefined is treated as active.

In `@web/src/__tests__/utils/dashboard.test.ts`:
- Around line 187-191: The helper function name dh is too terse and hurts
readability; rename the function dh to a more descriptive name like
makeDepartmentHealth or createDeptHealth across the file and update all call
sites in the test suite accordingly (e.g., rename the function declaration for
dh and replace every invocation of dh(...) with makeDepartmentHealth(...) so
imports/uses remain consistent while preserving the same parameters and return
type DepartmentHealth).

In `@web/src/pages/AgentDetailPage.tsx`:
- Line 74: Extract the inline type-filtering expression into a clearly named
local variable before the JSX return to improve readability: compute a const
like allowedTools (or similar) by checking Array.isArray(agent.tools['allowed'])
then filtering (agent.tools['allowed'] as unknown[]).filter((t): t is string =>
typeof t === 'string'), and pass that variable into <ToolBadges> instead of the
inline expression; update the JSX to ToolBadges tools={allowedTools} so the
logic is isolated from presentation.

In `@web/src/pages/org-edit/AgentEditDrawer.tsx`:
- Line 69: The current memoized formatter uses new Date(agent.hiring_date) which
can shift date-only strings across timezones and doesn't guard invalid dates;
update the function that returns agent?.hiring_date ? ... to parse date-only
strings safely (e.g., detect YYYY-MM-DD and construct a Date with Date.UTC(year,
month-1, day) or create with local year/month/day components), check the
resulting Date with isNaN(date.getTime()) and return '' for invalid values, and
change the memo dependency from [agent] to [agent?.hiring_date] so the memo only
recalculates when the hiring_date value changes.

In `@web/src/pages/org/build-org-tree.ts`:
- Around line 97-98: agent.name is being used as a fallback key when agent.id is
missing which can cause collisions; create a deterministic unique key generator
(e.g., function generateAgentKey(agent, index) or method on the agent object)
that returns agent.id when present and otherwise returns a synthesized stable
key built from multiple immutable agent properties (for example name + type +
createdAt or email) and/or the agent's index, and replace all usages that
currently fall back to agent.name (including the resolveRuntimeStatus call and
the other occurrences referenced) to use generateAgentKey(...) so runtime-status
lookups, node ids, edge ids, and CEO/head exclusion use this stable unique key.

In `@web/src/pages/org/DepartmentStatsBar.tsx`:
- Around line 16-25: Remove the hardcoded fallback currency and ensure the cost
pill only renders when a real currency is provided: update
DepartmentStatsBarProps/DepartmentStatsBar to not default currency = 'EUR' (make
currency required or optional without a default), and change the conditional
around the cost pill to check both cost7d is finite and currency is present
(e.g., if cost7d !== null && Number.isFinite(cost7d) && currency). Use
formatCurrency(cost7d, currency) only inside that guarded branch and keep
StatPill usage unchanged.

---

Outside diff comments:
In `@web/src/hooks/useAgentDetailData.ts`:
- Around line 110-126: The WebSocket bindings capture agentName at creation and
cause stale/no-op behavior on transitions; fix by making the handler read the
live ref and guard empty names instead of closing over agentName: in
useAgentDetailData update the binding factory (used to build bindings passed to
useWebSocket) so each handler does const name = agentNameRef.current; if (!name)
return; then perform the debounce and call
useAgentsStore.getState().fetchAgentDetail(name) (still using wsDebounceRef and
WS_DEBOUNCE_MS); keep DETAIL_CHANNELS and bindings structure but ensure handlers
never close over the outer agentName value so handlers remain valid across
agentName changes and won't call fetchAgentDetail('').
🪄 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: 3d2f9ea4-33ff-49cc-a42a-31821d8bcbbf

📥 Commits

Reviewing files that changed from the base of the PR and between 7479977 and 8d5a59a.

📒 Files selected for processing (18)
  • web/src/__tests__/components/ui/dept-health-bar.test.tsx
  • web/src/__tests__/hooks/useAgentDetailData.test.ts
  • web/src/__tests__/hooks/useAgentsData.test.ts
  • web/src/__tests__/pages/org-edit/DepartmentsTab.test.tsx
  • web/src/__tests__/pages/org/build-org-tree.test.ts
  • web/src/__tests__/stores/company.test.ts
  • web/src/__tests__/utils/agents.property.test.ts
  • web/src/__tests__/utils/agents.test.ts
  • web/src/__tests__/utils/dashboard.test.ts
  • web/src/hooks/useAgentDetailData.ts
  • web/src/hooks/useAgentsData.ts
  • web/src/pages/AgentDetailPage.tsx
  • web/src/pages/org-edit/AgentEditDrawer.tsx
  • web/src/pages/org/DepartmentGroupNode.stories.tsx
  • web/src/pages/org/DepartmentGroupNode.tsx
  • web/src/pages/org/DepartmentStatsBar.tsx
  • web/src/pages/org/build-org-tree.ts
  • web/src/stores/budget.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 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 (6)
web/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

web/src/**/*.{ts,tsx}: Web Dashboard: ALWAYS reuse existing components from web/src/components/ui/ before creating new ones. Reuse StatusBadge, MetricCard, Sparkline, SectionCard, AgentCard, DeptHealthBar, ProgressGauge, StatPill, Avatar, Button, Toast, Skeleton variants, EmptyState, ErrorBoundary, ConfirmDialog, CommandPalette, InlineEdit, AnimatedPresence, StaggerGroup, Drawer, InputField, SelectField, SliderField, ToggleField, TaskStatusIndicator, PriorityBadge, ProviderHealthBadge, TokenUsageBar, CodeMirrorEditor, SegmentedControl, ThemeToggle.
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 text-metric font-bold—use <MetricCard>. Do NOT render initials circles manually—use <Avatar>. Do NOT create complex (>8 line) JSX inside .map()—extract to a shared component.
Web design system enforcement: A PostToolUse hook (scripts/check_web_design_system.py) runs automatically on every Edit/Write to web/src/ files. It catches hardcoded hex colors, rgba values, font-family declarations, missing Storybook stories, duplicate patterns, and complex map blocks. Fix all violations before proceeding.
React 19 + shadcn/ui + Tailwind CSS 4 dashboard: Use React Router, Zustand stores, @tanstack/react-query, @xyflow/react, @dagrejs/dagre, d3-force, @dnd-kit, Recharts, Framer Motion, cmdk, js-yaml, Axios.

Files:

  • web/src/pages/AgentDetailPage.tsx
  • web/src/stores/budget.ts
  • web/src/__tests__/pages/org-edit/DepartmentsTab.test.tsx
  • web/src/__tests__/utils/agents.property.test.ts
  • web/src/__tests__/utils/agents.test.ts
  • web/src/__tests__/components/ui/dept-health-bar.test.tsx
  • web/src/pages/org/DepartmentGroupNode.stories.tsx
  • web/src/pages/org/DepartmentGroupNode.tsx
  • web/src/hooks/useAgentDetailData.ts
  • web/src/__tests__/stores/company.test.ts
  • web/src/pages/org-edit/AgentEditDrawer.tsx
  • web/src/__tests__/hooks/useAgentsData.test.ts
  • web/src/pages/org/DepartmentStatsBar.tsx
  • web/src/__tests__/pages/org/build-org-tree.test.ts
  • web/src/pages/org/build-org-tree.ts
  • web/src/hooks/useAgentsData.ts
  • web/src/__tests__/utils/dashboard.test.ts
  • web/src/__tests__/hooks/useAgentDetailData.test.ts
web/src/**/*.{ts,tsx,css}

📄 CodeRabbit inference engine (CLAUDE.md)

Design tokens: Colors use Tailwind semantic classes (text-foreground, bg-card, text-accent, etc.) or CSS variables (var(--so-accent)). NEVER hardcode hex values. Typography uses font-sans or font-mono. Spacing uses density-aware tokens or standard Tailwind. Shadows/borders use token variables.

Files:

  • web/src/pages/AgentDetailPage.tsx
  • web/src/stores/budget.ts
  • web/src/__tests__/pages/org-edit/DepartmentsTab.test.tsx
  • web/src/__tests__/utils/agents.property.test.ts
  • web/src/__tests__/utils/agents.test.ts
  • web/src/__tests__/components/ui/dept-health-bar.test.tsx
  • web/src/pages/org/DepartmentGroupNode.stories.tsx
  • web/src/pages/org/DepartmentGroupNode.tsx
  • web/src/hooks/useAgentDetailData.ts
  • web/src/__tests__/stores/company.test.ts
  • web/src/pages/org-edit/AgentEditDrawer.tsx
  • web/src/__tests__/hooks/useAgentsData.test.ts
  • web/src/pages/org/DepartmentStatsBar.tsx
  • web/src/__tests__/pages/org/build-org-tree.test.ts
  • web/src/pages/org/build-org-tree.ts
  • web/src/hooks/useAgentsData.ts
  • web/src/__tests__/utils/dashboard.test.ts
  • web/src/__tests__/hooks/useAgentDetailData.test.ts
**/*.{ts,tsx,json}

📄 CodeRabbit inference engine (CLAUDE.md)

TypeScript 6.0: Remove baseUrl (deprecated); paths entries are relative to tsconfig directory. esModuleInterop always true—cannot be set to false. types defaults to []—must explicitly list (e.g. 'types': ['vitest/globals']). DOM.Iterable merged into DOM. moduleResolution: 'classic' and 'node10' removed—use 'bundler' or 'nodenext'. strict defaults to true. noUncheckedSideEffectImports defaults to true.

Files:

  • web/src/pages/AgentDetailPage.tsx
  • web/src/stores/budget.ts
  • web/src/__tests__/pages/org-edit/DepartmentsTab.test.tsx
  • web/src/__tests__/utils/agents.property.test.ts
  • web/src/__tests__/utils/agents.test.ts
  • web/src/__tests__/components/ui/dept-health-bar.test.tsx
  • web/src/pages/org/DepartmentGroupNode.stories.tsx
  • web/src/pages/org/DepartmentGroupNode.tsx
  • web/src/hooks/useAgentDetailData.ts
  • web/src/__tests__/stores/company.test.ts
  • web/src/pages/org-edit/AgentEditDrawer.tsx
  • web/src/__tests__/hooks/useAgentsData.test.ts
  • web/src/pages/org/DepartmentStatsBar.tsx
  • web/src/__tests__/pages/org/build-org-tree.test.ts
  • web/src/pages/org/build-org-tree.ts
  • web/src/hooks/useAgentsData.ts
  • web/src/__tests__/utils/dashboard.test.ts
  • web/src/__tests__/hooks/useAgentDetailData.test.ts
**/*.{py,ts,tsx,go}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{py,ts,tsx,go}: Lint & format: Python via ruff (uv run ruff check + uv run ruff format). TypeScript web via ESLint (zero warnings enforced: npm --prefix web run lint). Go CLI via golangci-lint and go vet. All enforced in pre-commit hooks.
Type checking: Python via mypy strict mode (uv run mypy src/ tests/). TypeScript via npm --prefix web run type-check. Go via go -C cli vet ./....

Files:

  • web/src/pages/AgentDetailPage.tsx
  • web/src/stores/budget.ts
  • web/src/__tests__/pages/org-edit/DepartmentsTab.test.tsx
  • web/src/__tests__/utils/agents.property.test.ts
  • web/src/__tests__/utils/agents.test.ts
  • web/src/__tests__/components/ui/dept-health-bar.test.tsx
  • web/src/pages/org/DepartmentGroupNode.stories.tsx
  • web/src/pages/org/DepartmentGroupNode.tsx
  • web/src/hooks/useAgentDetailData.ts
  • web/src/__tests__/stores/company.test.ts
  • web/src/pages/org-edit/AgentEditDrawer.tsx
  • web/src/__tests__/hooks/useAgentsData.test.ts
  • web/src/pages/org/DepartmentStatsBar.tsx
  • web/src/__tests__/pages/org/build-org-tree.test.ts
  • web/src/pages/org/build-org-tree.ts
  • web/src/hooks/useAgentsData.ts
  • web/src/__tests__/utils/dashboard.test.ts
  • web/src/__tests__/hooks/useAgentDetailData.test.ts
web/src/pages/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Web dashboard pages: Lazy-loaded page components (one per route). Page-scoped sub-components in pages/<page-name>/ subdirs. Feature dirs added as pages are built. Stores for auth, WebSocket, toast, analytics, setup wizard, company, agents, budget, tasks, settings, providers, theme.

Files:

  • web/src/pages/AgentDetailPage.tsx
  • web/src/pages/org/DepartmentGroupNode.stories.tsx
  • web/src/pages/org/DepartmentGroupNode.tsx
  • web/src/pages/org-edit/AgentEditDrawer.tsx
  • web/src/pages/org/DepartmentStatsBar.tsx
  • web/src/pages/org/build-org-tree.ts
web/**/*.stories.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Storybook 10: ESM-only—no CJS support. Packages like @storybook/addon-essentials, @storybook/addon-interactions, @storybook/test, @storybook/blocks no longer published. @storybook/addon-docs is separate. Import from storybook/test (not @storybook/test), storybook/actions. Use defineMain from @storybook/react-vite/node and definePreview from @storybook/react-vite. Backgrounds API: use parameters.backgrounds.options (object) + initialGlobals.backgrounds.value. a11y testing: use parameters.a11y.test: 'error' | 'todo' | 'off'. Minimum versions: Node 20.19+, Vite 5+, Vitest 3+, TypeScript 4.9+.

Files:

  • web/src/pages/org/DepartmentGroupNode.stories.tsx
🧠 Learnings (7)
📓 Common learnings
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-29T11:41:44.483Z
Learning: Applies to web/src/**/*.{ts,tsx} : Web Dashboard: ALWAYS reuse existing components from `web/src/components/ui/` before creating new ones. Reuse StatusBadge, MetricCard, Sparkline, SectionCard, AgentCard, DeptHealthBar, ProgressGauge, StatPill, Avatar, Button, Toast, Skeleton variants, EmptyState, ErrorBoundary, ConfirmDialog, CommandPalette, InlineEdit, AnimatedPresence, StaggerGroup, Drawer, InputField, SelectField, SliderField, ToggleField, TaskStatusIndicator, PriorityBadge, ProviderHealthBadge, TokenUsageBar, CodeMirrorEditor, SegmentedControl, ThemeToggle.
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-29T11:41:44.483Z
Learning: Applies to web/src/**/*.{ts,tsx} : React 19 + shadcn/ui + Tailwind CSS 4 dashboard: Use React Router, Zustand stores, tanstack/react-query, xyflow/react, dagrejs/dagre, d3-force, dnd-kit, Recharts, Framer Motion, cmdk, js-yaml, Axios.
📚 Learning: 2026-03-29T11:41:44.483Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-29T11:41:44.483Z
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 `text-metric font-bold`—use `<MetricCard>`. Do NOT render initials circles manually—use `<Avatar>`. Do NOT create complex (>8 line) JSX inside `.map()`—extract to a shared component.

Applied to files:

  • web/src/pages/AgentDetailPage.tsx
  • web/src/__tests__/components/ui/dept-health-bar.test.tsx
  • web/src/pages/org-edit/AgentEditDrawer.tsx
  • web/src/pages/org/DepartmentStatsBar.tsx
📚 Learning: 2026-03-29T11:41:44.483Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-29T11:41:44.483Z
Learning: Applies to web/src/**/*.{ts,tsx} : Web Dashboard: ALWAYS reuse existing components from `web/src/components/ui/` before creating new ones. Reuse StatusBadge, MetricCard, Sparkline, SectionCard, AgentCard, DeptHealthBar, ProgressGauge, StatPill, Avatar, Button, Toast, Skeleton variants, EmptyState, ErrorBoundary, ConfirmDialog, CommandPalette, InlineEdit, AnimatedPresence, StaggerGroup, Drawer, InputField, SelectField, SliderField, ToggleField, TaskStatusIndicator, PriorityBadge, ProviderHealthBadge, TokenUsageBar, CodeMirrorEditor, SegmentedControl, ThemeToggle.

Applied to files:

  • web/src/pages/AgentDetailPage.tsx
  • web/src/hooks/useAgentDetailData.ts
  • web/src/pages/org-edit/AgentEditDrawer.tsx
  • web/src/hooks/useAgentsData.ts
  • web/src/__tests__/utils/dashboard.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-edit/DepartmentsTab.test.tsx
  • web/src/__tests__/components/ui/dept-health-bar.test.tsx
  • web/src/__tests__/utils/dashboard.test.ts
📚 Learning: 2026-03-29T11:41:44.483Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-29T11:41:44.483Z
Learning: Applies to web/src/components/ui/**/*.{ts,tsx} : Web components: Place new shared components in `web/src/components/ui/` with kebab-case filenames. Create `.stories.tsx` with all states. Export props as TypeScript interface. Use design tokens exclusively—no hardcoded colors, fonts, or spacing. Import `cn` from `@/lib/utils` for conditional class merging.

Applied to files:

  • web/src/__tests__/components/ui/dept-health-bar.test.tsx
📚 Learning: 2026-03-29T11:41:44.483Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-29T11:41:44.483Z
Learning: Applies to web/**/*.stories.{ts,tsx} : Storybook 10: ESM-only—no CJS support. Packages like `storybook/addon-essentials`, `storybook/addon-interactions`, `storybook/test`, `storybook/blocks` no longer published. `storybook/addon-docs` is separate. Import from `storybook/test` (not `storybook/test`), `storybook/actions`. Use `defineMain` from `storybook/react-vite/node` and `definePreview` from `storybook/react-vite`. Backgrounds API: use `parameters.backgrounds.options` (object) + `initialGlobals.backgrounds.value`. a11y testing: use `parameters.a11y.test: 'error' | 'todo' | 'off'`. Minimum versions: Node 20.19+, Vite 5+, Vitest 3+, TypeScript 4.9+.

Applied to files:

  • web/src/pages/org/DepartmentGroupNode.stories.tsx
📚 Learning: 2026-03-29T11:41:44.483Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-29T11:41:44.483Z
Learning: Applies to web/src/**/*.{ts,tsx} : React 19 + shadcn/ui + Tailwind CSS 4 dashboard: Use React Router, Zustand stores, tanstack/react-query, xyflow/react, dagrejs/dagre, d3-force, dnd-kit, Recharts, Framer Motion, cmdk, js-yaml, Axios.

Applied to files:

  • web/src/pages/org/DepartmentGroupNode.tsx
  • web/src/hooks/useAgentDetailData.ts
  • web/src/hooks/useAgentsData.ts
🔇 Additional comments (15)
web/src/__tests__/pages/org-edit/DepartmentsTab.test.tsx (2)

13-13: Good fixture alignment with renamed health schema.

Line 13 correctly uses utilization_percent in test data, which matches the updated DepartmentHealth shape and avoids legacy-field drift.


46-52: Nice strengthening of value-level rendering coverage.

Lines 51-52 correctly assert 72%, so the test now verifies the mapped utilization_percent output—not just meter presence.

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

125-130: Identifier fallback mapping is now correctly hardened.

This block now indexes agentNameMap/agentDeptMap by both agent.name and agent.id (when present), which aligns with downstream lookups keyed by agent_id and avoids silent Unknown/raw-ID fallbacks.

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

53-61: DepartmentHealth fixture alignment looks correct.

The updated mock shape (department_name, department_cost_7d, utilization_percent, etc.) is consistent with the backend-aligned DepartmentHealth contract.


158-158: Assertion key rename is correct.

Using department_name here keeps the failed-fetch filtering test aligned with the updated health payload structure.


392-392: Reorder ID fallback expectation is correctly updated.

Switching to a.id ?? a.name matches the store’s idOf logic, so this test now correctly covers agents without id.

Also applies to: 400-400, 406-406

web/src/__tests__/components/ui/dept-health-bar.test.tsx (2)

31-63: Prop-aligned test updates look correct.

These updated renders are consistent with the current DeptHealthBar API (no taskCount) and keep each behavior test focused.


89-101: Great nullable-health coverage added.

Validating both null and undefined with N/A plus no meter role is a solid regression guard for fallback behavior.

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

40-40: arbAgent now correctly mirrors the updated AgentConfig shape.

Optional id/status generation and required authority inclusion are aligned with the backend-synced type contract.

Also applies to: 48-48, 74-74

web/src/__tests__/utils/dashboard.test.ts (2)

187-203: Past review feedback has been addressed.

The helper function now correctly types the name parameter as DepartmentHealth['department_name'] and removes the inline cast, making the fixture strongly typed.


210-232: Excellent test coverage for computeOrgHealth.

The tests comprehensively cover the production behavior: aggregation of utilization_percent, rounding, and filtering of non-finite values (NaN/Infinity). The new tests at lines 222-232 correctly verify the filtering logic that matches the production implementation's use of Number.isFinite(d.utilization_percent).

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

54-68: Debounced WS refetch flow looks correct.

Good trailing-edge debounce wiring and cleanup; this avoids burst refetch storms and prevents post-unmount timer execution.

web/src/__tests__/hooks/useAgentsData.test.ts (1)

132-195: Debounce test matrix is solid.

Nice coverage of trailing behavior, coalescing, reset semantics, and unmount cleanup for WS-triggered refetches.

web/src/pages/org-edit/AgentEditDrawer.tsx (2)

56-56: Consistent nullish-status fallback is solid.

Using 'active' as the shared fallback in state init, badge display, and select value keeps behavior consistent with optional AgentConfig.status.

Also applies to: 122-123, 155-155


72-78: Model display narrowing is correctly hardened.

Filtering to string-only provider/model_id parts and rendering conditionally avoids [object Object] output and stray separators.

Also applies to: 162-164

Comment on lines +179 to +259
describe('WebSocket debounce', () => {
let wsHandler: (...args: unknown[]) => void

async function setupHandler() {
const { useWebSocket } = await import('@/hooks/useWebSocket')
renderHook(() => useAgentDetailData('alice'))
const bindings = vi.mocked(useWebSocket).mock.calls[0]![0].bindings
wsHandler = bindings[0]!.handler as (...args: unknown[]) => void
// Clear the initial fetchAgentDetail call from mount
mockFetchAgentDetail.mockClear()
}

beforeEach(() => {
vi.useFakeTimers()
})

afterEach(() => {
vi.useRealTimers()
})

it('does not call fetchAgentDetail synchronously on WS event', async () => {
await setupHandler()
wsHandler()
expect(mockFetchAgentDetail).not.toHaveBeenCalled()
})

it('calls fetchAgentDetail after 300ms debounce', async () => {
await setupHandler()
wsHandler()
vi.advanceTimersByTime(300)
expect(mockFetchAgentDetail).toHaveBeenCalledTimes(1)
expect(mockFetchAgentDetail).toHaveBeenCalledWith('alice')
})

it('coalesces burst events into a single fetch', async () => {
await setupHandler()
for (let i = 0; i < 5; i++) wsHandler()
vi.advanceTimersByTime(300)
expect(mockFetchAgentDetail).toHaveBeenCalledTimes(1)
})

it('resets debounce timer on subsequent event within window', async () => {
await setupHandler()
wsHandler()
vi.advanceTimersByTime(200)
wsHandler() // resets the 300ms window
vi.advanceTimersByTime(200)
expect(mockFetchAgentDetail).not.toHaveBeenCalled() // only 200ms since last event
vi.advanceTimersByTime(100)
expect(mockFetchAgentDetail).toHaveBeenCalledTimes(1)
expect(mockFetchAgentDetail).toHaveBeenCalledWith('alice')
})

it('cleans up timeout on unmount', async () => {
const { useWebSocket } = await import('@/hooks/useWebSocket')
const { unmount } = renderHook(() => useAgentDetailData('alice'))
const bindings = vi.mocked(useWebSocket).mock.calls[0]![0].bindings
const handler = bindings[0]!.handler as (...args: unknown[]) => void
mockFetchAgentDetail.mockClear()

handler()
unmount()
vi.advanceTimersByTime(300)
expect(mockFetchAgentDetail).not.toHaveBeenCalled()
})

it('coalesces events across agents and tasks channels', async () => {
const { useWebSocket } = await import('@/hooks/useWebSocket')
renderHook(() => useAgentDetailData('alice'))
const bindings = vi.mocked(useWebSocket).mock.calls[0]![0].bindings
const agentsHandler = bindings[0]!.handler as (...args: unknown[]) => void
const tasksHandler = bindings[1]!.handler as (...args: unknown[]) => void
mockFetchAgentDetail.mockClear()

agentsHandler()
tasksHandler()
agentsHandler()
vi.advanceTimersByTime(300)
expect(mockFetchAgentDetail).toHaveBeenCalledTimes(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

Add transition regression tests for agentName lifecycle.

Please add a rerender case for '' -> 'alice' and 'alice' -> '' to validate WS handler setup/teardown behavior across param transitions, not only steady-state debounce timing.

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

In `@web/src/__tests__/hooks/useAgentDetailData.test.ts` around lines 179 - 259,
Add tests that exercise agentName prop transitions by rendering
useAgentDetailData with '' then rerendering to 'alice' and vice versa to verify
WebSocket handler setup/teardown; specifically, in the WebSocket debounce suite
add two cases: one that calls renderHook(() => useAgentDetailData('')) then
rerender('alice'), fetches the new bindings from
vi.mocked(useWebSocket).mock.calls[0][0].bindings, triggers the handler(s),
advances timers and asserts mockFetchAgentDetail was called with 'alice'; and a
reverse case that starts with 'alice', rerenders to '' and asserts the previous
handlers were cleaned up (trigger handler after rerender/unmount and advance
timers to confirm mockFetchAgentDetail is not called). Ensure you reuse
setupHandler pattern (useWebSocket, wsHandler/agentsHandler/tasksHandler), clear
mockFetchAgentDetail between steps, and call
vi.useFakeTimers()/vi.useRealTimers() as in existing tests.

Comment on lines +219 to +229
it('treats agent with undefined status as active for sorting', () => {
const withUndefined = [
makeAgent({ name: 'Active Agent', status: 'active' }),
makeAgent({ name: 'No Status', status: undefined }),
makeAgent({ name: 'Terminated Agent', status: 'terminated' }),
]
const result = sortAgents(withUndefined, 'status', 'asc')
// undefined status treated as 'active' -- should sort with active agents, before terminated
const names = result.map((a) => a.name)
expect(names.indexOf('Terminated Agent')).toBeGreaterThan(names.indexOf('No Status'))
})
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

Cover the undefined => active sort case more precisely.

This only proves undefined sorts before terminated. If sortAgents accidentally ranked a missing status as onboarding, this test would still pass. Add an explicit onboarding case and assert No Status sorts ahead of it.

💡 Tighten the expectation
   const withUndefined = [
     makeAgent({ name: 'Active Agent', status: 'active' }),
     makeAgent({ name: 'No Status', status: undefined }),
+    makeAgent({ name: 'Onboarding Agent', status: 'onboarding' }),
     makeAgent({ name: 'Terminated Agent', status: 'terminated' }),
   ]
   const result = sortAgents(withUndefined, 'status', 'asc')
-  // undefined status treated as 'active' -- should sort with active agents, before terminated
   const names = result.map((a) => a.name)
+  expect(names.indexOf('No Status')).toBeLessThan(names.indexOf('Onboarding Agent'))
   expect(names.indexOf('Terminated Agent')).toBeGreaterThan(names.indexOf('No Status'))
📝 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('treats agent with undefined status as active for sorting', () => {
const withUndefined = [
makeAgent({ name: 'Active Agent', status: 'active' }),
makeAgent({ name: 'No Status', status: undefined }),
makeAgent({ name: 'Terminated Agent', status: 'terminated' }),
]
const result = sortAgents(withUndefined, 'status', 'asc')
// undefined status treated as 'active' -- should sort with active agents, before terminated
const names = result.map((a) => a.name)
expect(names.indexOf('Terminated Agent')).toBeGreaterThan(names.indexOf('No Status'))
})
it('treats agent with undefined status as active for sorting', () => {
const withUndefined = [
makeAgent({ name: 'Active Agent', status: 'active' }),
makeAgent({ name: 'No Status', status: undefined }),
makeAgent({ name: 'Onboarding Agent', status: 'onboarding' }),
makeAgent({ name: 'Terminated Agent', status: 'terminated' }),
]
const result = sortAgents(withUndefined, 'status', 'asc')
const names = result.map((a) => a.name)
expect(names.indexOf('No Status')).toBeLessThan(names.indexOf('Onboarding Agent'))
expect(names.indexOf('Terminated Agent')).toBeGreaterThan(names.indexOf('No Status'))
})
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/__tests__/utils/agents.test.ts` around lines 219 - 229, Update the
test "treats agent with undefined status as active for sorting" to include an
explicit onboarding case so undefined isn't accidentally treated as onboarding;
add makeAgent({ name: 'Onboarding Agent', status: 'onboarding' }) to the
withUndefined array and then assert that names.indexOf('No Status') is less than
names.indexOf('Onboarding Agent') (and keep/assert that it's also less than
names.indexOf('Terminated Agent') if desired) to ensure undefined is treated as
active.

Comment on lines +187 to +191
function dh(
name: DepartmentHealth['department_name'],
utilization: number,
agents = 1,
): DepartmentHealth {
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

Consider a more descriptive helper function name.

The helper name dh is quite terse. While short names are sometimes acceptable in test files, a more descriptive name like makeDepartmentHealth or createDeptHealth would improve readability and make the test code more self-documenting.

♻️ Proposed refactor
-function dh(
+function makeDepartmentHealth(
   name: DepartmentHealth['department_name'],
   utilization: number,
   agents = 1,
 ): DepartmentHealth {

Then update all call sites:

-    expect(computeOrgHealth([dh('engineering', 85, 4)])).toBe(85)
+    expect(computeOrgHealth([makeDepartmentHealth('engineering', 85, 4)])).toBe(85)
📝 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
function dh(
name: DepartmentHealth['department_name'],
utilization: number,
agents = 1,
): DepartmentHealth {
function makeDepartmentHealth(
name: DepartmentHealth['department_name'],
utilization: number,
agents = 1,
): DepartmentHealth {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/__tests__/utils/dashboard.test.ts` around lines 187 - 191, The helper
function name dh is too terse and hurts readability; rename the function dh to a
more descriptive name like makeDepartmentHealth or createDeptHealth across the
file and update all call sites in the test suite accordingly (e.g., rename the
function declaration for dh and replace every invocation of dh(...) with
makeDepartmentHealth(...) so imports/uses remain consistent while preserving the
same parameters and return type DepartmentHealth).

)
const hiredDate = useMemo(
() => agent ? new Date(agent.hiring_date).toLocaleDateString() : '',
() => agent?.hiring_date ? new Date(agent.hiring_date).toLocaleDateString() : '',
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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "1) Locate AgentConfig + hiring_date typing"
rg -n -C3 --type=ts '\b(AgentConfig|hiring_date)\b'

echo
echo "2) Find date-only hiring_date fixtures/usages (YYYY-MM-DD)"
rg -n -C2 --type=ts --type=tsx "hiring_date\\s*[:=]\\s*['\"][0-9]{4}-[0-9]{2}-[0-9]{2}['\"]"

echo
echo "3) Find datetime hiring_date fixtures/usages (ISO timestamp)"
rg -n -C2 --type=ts --type=tsx "hiring_date\\s*[:=]\\s*['\"][0-9]{4}-[0-9]{2}-[0-9]{2}T"

Repository: Aureliolo/synthorg

Length of output: 50419


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== 1. Find formatDate implementation ==="
rg -n "export.*formatDate" web/src/utils/

echo
echo "=== 2. Show formatDate full implementation ==="
rg -A 15 "export.*function formatDate" web/src/utils/

echo
echo "=== 3. Check how AgentIdentityHeader uses formatDate ==="
rg -B 2 -A 2 "formatDate.*hiring" web/src/pages/agents/

echo
echo "=== 4. See if there's a formatRelativeTime as well ==="
rg -A 10 "export.*function formatRelativeTime" web/src/utils/

echo
echo "=== 5. Check actual test coverage for date parsing edge cases ==="
rg -n "hiring_date" web/src/__tests__/utils/ | head -20

Repository: Aureliolo/synthorg

Length of output: 3579


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Check AgentEditDrawer usage of hiredDate ==="
rg -A 20 "const hiredDate = useMemo" web/src/pages/org-edit/AgentEditDrawer.tsx

echo
echo "=== Check where hiredDate is rendered ==="
rg -B 3 -A 3 "hiredDate" web/src/pages/org-edit/AgentEditDrawer.tsx

echo
echo "=== Full context of the file around line 69 ==="
sed -n '60,180p' web/src/pages/org-edit/AgentEditDrawer.tsx

Repository: Aureliolo/synthorg

Length of output: 5391


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Check backend schema/docs for hiring_date format ==="
fd -type f \( -name "*.md" -o -name "*.py" \) | xargs grep -l "hiring_date" 2>/dev/null | head -5

echo
echo "=== Search for backend schema definition ==="
find . -path ./node_modules -prune -o -name "schema*.py" -o -name "*config*.py" | xargs grep -l "hiring_date" 2>/dev/null

echo
echo "=== Check API response examples/fixtures ==="
rg "hiring_date" web/src/api/ -A 2 -B 2

echo
echo "=== Check if there's any documentation or migration notes ==="
fd -type f \( -name "CHANGELOG*" -o -name "README*" \) | xargs grep -i "hiring" 2>/dev/null

Repository: Aureliolo/synthorg

Length of output: 308


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Search for backend schema files ==="
find . -name "*.py" -path "*/config/*" -o -name "schema.py" 2>/dev/null | head -10

echo
echo "=== Check for hiring_date in backend config/schema ==="
rg "hiring_date" --type=py -B 3 -A 3 2>/dev/null | head -40

echo
echo "=== Look for API documentation or README ==="
ls -la README* CHANGELOG* 2>/dev/null | head -5

echo
echo "=== Check if date-only format is referenced in tests or comments ==="
rg "hiring_date.*YYYY|date-only|2026-01-01[^T]" -B 2 -A 2 2>/dev/null

Repository: Aureliolo/synthorg

Length of output: 3247


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Check AgentConfig schema in backend ==="
rg -A 20 "class AgentConfig" src/synthorg/config/schema.py

echo
echo "=== Check how hiring_date is typed and serialized ==="
rg -B 5 -A 5 "hiring_date" src/synthorg/config/schema.py

echo
echo "=== Check API serialization/JSON encoding ==="
fd -name "*.py" -path "*/api/*" -o -path "*/routes/*" | xargs grep -l "hiring_date" 2>/dev/null | head -3

Repository: Aureliolo/synthorg

Length of output: 1602


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Check AgentIdentity class for hiring_date ==="
rg "class AgentIdentity" src/synthorg/ -A 30 | head -50

echo
echo "=== Find where hiring_date is set/serialized ==="
rg "hiring_date" src/synthorg/ --type=py | grep -E "(date\(|datetime|isoformat|strftime)" | head -10

echo
echo "=== Check core agent model ==="
rg -A 5 "hiring_date" src/synthorg/core/agent.py | head -30

Repository: Aureliolo/synthorg

Length of output: 2800


Add Invalid Date guard and use date-only safe parsing for hiring_date.

Date-only strings like "2026-01-01" parsed via new Date() will shift backward in US timezones (interpreted as UTC midnight). Add a guard for invalid dates and parse date-only values safely:

Suggested fix
-  const hiredDate = useMemo(
-    () => agent?.hiring_date ? new Date(agent.hiring_date).toLocaleDateString() : '',
-    [agent],
-  )
+  const hiredDate = useMemo(() => {
+    if (!agent?.hiring_date) return ''
+    const parsed = new Date(agent.hiring_date)
+    return Number.isNaN(parsed.getTime()) ? '' : parsed.toLocaleDateString()
+  }, [agent?.hiring_date])

Also update the dependency array from [agent] to [agent?.hiring_date] to avoid unnecessary memoization.

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

In `@web/src/pages/org-edit/AgentEditDrawer.tsx` at line 69, The current memoized
formatter uses new Date(agent.hiring_date) which can shift date-only strings
across timezones and doesn't guard invalid dates; update the function that
returns agent?.hiring_date ? ... to parse date-only strings safely (e.g., detect
YYYY-MM-DD and construct a Date with Date.UTC(year, month-1, day) or create with
local year/month/day components), check the resulting Date with
isNaN(date.getTime()) and return '' for invalid values, and change the memo
dependency from [agent] to [agent?.hiring_date] so the memo only recalculates
when the hiring_date value changes.

Comment on lines +16 to +25
cost7d,
currency = 'EUR',
className,
}: DepartmentStatsBarProps) {
return (
<div className={cn('flex flex-wrap gap-1.5', className)} data-testid="dept-stats-bar">
<StatPill label="Agents" value={agentCount} />
<StatPill label="Active" value={activeCount} />
<StatPill label="Tasks" value={taskCount} />
{costUsd !== null && <StatPill label="Cost" value={formatCurrency(costUsd, currency)} />}
{cost7d !== null && Number.isFinite(cost7d) && (
<StatPill label="Cost (7d)" value={formatCurrency(cost7d, currency)} />
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 hardcode 'EUR' as the fallback currency.

cost7d and currency now travel together from backend health data. Defaulting to EUR here turns a missing prop into a plausible-but-wrong money value instead of surfacing the data bug. Require currency when rendering the pill, or skip the cost pill when it's absent.

💡 Safer rendering contract
 interface DepartmentStatsBarProps {
   agentCount: number
   activeCount: number
   cost7d: number | null
-  currency?: string
+  currency?: string | null
   className?: string
 }
 
 export function DepartmentStatsBar({
   agentCount,
   activeCount,
   cost7d,
-  currency = 'EUR',
+  currency,
   className,
 }: DepartmentStatsBarProps) {
   return (
     <div className={cn('flex flex-wrap gap-1.5', className)} data-testid="dept-stats-bar">
       <StatPill label="Agents" value={agentCount} />
       <StatPill label="Active" value={activeCount} />
-      {cost7d !== null && Number.isFinite(cost7d) && (
+      {cost7d !== null && Number.isFinite(cost7d) && currency && (
         <StatPill label="Cost (7d)" value={formatCurrency(cost7d, currency)} />
       )}
     </div>
   )
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/pages/org/DepartmentStatsBar.tsx` around lines 16 - 25, Remove the
hardcoded fallback currency and ensure the cost pill only renders when a real
currency is provided: update DepartmentStatsBarProps/DepartmentStatsBar to not
default currency = 'EUR' (make currency required or optional without a default),
and change the conditional around the cost pill to check both cost7d is finite
and currency is present (e.g., if cost7d !== null && Number.isFinite(cost7d) &&
currency). Use formatCurrency(cost7d, currency) only inside that guarded branch
and keep StatPill usage unchanged.

Aureliolo and others added 7 commits March 29, 2026 23:01
Update DepartmentHealth interface to match the backend Pydantic model:
rename name->department_name, health_percent->utilization_percent,
cost_usd->department_cost_7d; remove display_name and task_count;
add active_agent_count, currency, avg_performance_score, cost_trend,
collaboration_score. Cascade to all 20+ consumer files including
DeptHealthBar (remove taskCount prop), DepartmentStatsBar
(remove taskCount, rename costUsd->cost7d), DepartmentGroupData,
OrgHealthSection, build-org-tree, stores, tests, and stories.

Closes #892

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

Make id, status, hiring_date optional (they are AgentIdentity runtime
fields not present in backend AgentConfig). Remove skills (unused by
any component). Change personality, model, memory, tools from typed
interfaces to Record<string, unknown> to match backend dict[str, Any].
Add optional authority field. All consumers now use fallbacks:
agent.id ?? agent.name, agent.status ?? 'active', conditional render
for hiring_date. Cascade to build-org-tree, AgentGridView,
AgentIdentityHeader, AgentEditDrawer, AgentsTab, company store,
budget store, utils/agents, and all stories/tests.

Closes #878

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

Define ActivityEventType with 13 known values matching backend event
types (hired, fired, promoted, demoted, onboarded, offboarded,
status_changed, task_completed, task_started, cost_incurred, tool_used,
delegation_sent, delegation_received). Use in AgentActivityEvent with
(string & {}) fallback for unknown future types. Type-narrow
ACTIVITY_ICON_MAP to Partial<Record<ActivityEventType, LucideIcon>>.

Closes #877

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add 300ms debounce to WebSocket event handlers in useAgentsData and
useAgentDetailData to coalesce burst events (e.g. batch agent updates)
into a single API refetch. Uses useRef for the timeout ID so the
handler closure captured on mount always accesses the current timer.
Cleanup effect clears pending timeouts on unmount. Add 4 tests per
hook: sync suppression, debounce firing, burst coalescing, and
unmount cleanup.

Closes #876

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Pre-reviewed by 5 agents, 11 findings addressed:
- Remove dead interfaces (PersonalityConfig, ModelConfig, SkillSet,
  MemoryConfig, ToolPermissions) from types.ts
- Make authority required on AgentConfig (backend always sends {})
- Replace as string[] cast with runtime type filter in AgentDetailPage
- Fix wsDebouncRef typo -> wsDebounceRef in both hooks
- Update CLAUDE.md and brand-and-ux.md DeptHealthBar inventory
- Add JSDoc on range-bounded DepartmentHealth fields
- Add tests for id:undefined and status:undefined fallback paths
- Add cross-channel debounce coalescing test

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

Thread per-department currency through org-chart nodes (was hardcoding
EUR fallback). Use typeof guards for Record<string, unknown> property
access in AgentEditDrawer and AgentDetailPage. Harden budget store
agent lookup maps to register both id and name keys. Clear debounce
timer on agentName changes (not just unmount). Guard DepartmentStatsBar
cost rendering against NaN/Infinity.

Add 5 new tests: DeptHealthBar null/undefined health, sortAgents with
undefined status, trailing-edge debounce reset for both hooks. Fix
company store test assertions to use id ?? name fallback. Tighten
dashboard test fixture typing. Add undefined status to property test
arbitrary. Assert rendered percentage in DepartmentsTab test.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Strengthen undefined-status sort test to verify same-rank ordering with
explicit active agents. Extract dense tools.allowed filtering in
AgentDetailPage to a named variable for readability.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@Aureliolo Aureliolo force-pushed the fix/type-alignment-websocket branch from 8d5a59a to df79937 Compare March 29, 2026 21:06
@Aureliolo Aureliolo temporarily deployed to cloudflare-preview March 29, 2026 21:07 — with GitHub Actions Inactive
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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
web/src/pages/agents/AgentGridView.stories.tsx (1)

49-61: 🧹 Nitpick | 🔵 Trivial

Consider adding a11y testing parameter.

Other stories in this PR include parameters: { a11y: { test: 'error' } }. Adding this would ensure accessibility testing consistency across stories.

♻️ Suggested addition
 const meta = {
   title: 'Agents/AgentGridView',
   component: AgentGridView,
+  parameters: {
+    a11y: { test: 'error' },
+  },
   decorators: [
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/pages/agents/AgentGridView.stories.tsx` around lines 49 - 61, The
story meta for AgentGridView is missing the accessibility testing parameter;
update the meta object (the const meta that satisfies Meta<typeof
AgentGridView>) to include parameters: { a11y: { test: 'error' } } so the story
enables the same a11y testing as other stories in the PR.
web/src/pages/org-edit/AgentEditDrawer.tsx (1)

48-62: ⚠️ Potential issue | 🟠 Major

Move state synchronization out of render.

Lines 48–62 call setForm, setSubmitError, setDeleteOpen, and setDeleting during render, which violates React's rules and can cause Strict Mode warnings and render churn. Move this logic into useEffect([agent]).

♻️ Proposed fix
-import { useCallback, useMemo, useRef, useState } from 'react'
+import { useCallback, useEffect, useMemo, useState } from 'react'
@@
-  const prevAgentRef = useRef<typeof agent | undefined>(undefined)
-  if (agent !== prevAgentRef.current) {
-    prevAgentRef.current = agent
-    if (agent) {
-      setForm({
-        name: agent.name,
-        role: agent.role,
-        department: agent.department,
-        level: agent.level,
-        status: agent.status ?? 'active',
-      })
-      setSubmitError(null)
-    }
-    setDeleteOpen(false)
-    setDeleting(false)
-  }
+  useEffect(() => {
+    if (agent) {
+      setForm({
+        name: agent.name,
+        role: agent.role,
+        department: agent.department,
+        level: agent.level,
+        status: agent.status ?? 'active',
+      })
+      setSubmitError(null)
+    }
+    setDeleteOpen(false)
+    setDeleting(false)
+  }, [agent])
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/pages/org-edit/AgentEditDrawer.tsx` around lines 48 - 62, The
state-sync block that compares agent to prevAgentRef.current and calls setForm,
setSubmitError, setDeleteOpen, and setDeleting should be moved out of render
into a useEffect that depends on agent; create a useEffect(() => { ... },
[agent]) which performs the same logic (update prevAgentRef.current, call
setForm with agent fields, setSubmitError(null), setDeleteOpen(false),
setDeleting(false)) and remove the inline state updates from the render path so
only pure reads occur during render and all side-effects run inside the
useEffect.
♻️ Duplicate comments (6)
web/src/hooks/useAgentsData.ts (1)

9-10: 🧹 Nitpick | 🔵 Trivial

Extract shared WS debounce policy into a single helper/module.

WS_DEBOUNCE_MS and timeout reset logic are duplicated here and in useAgentDetailData. Centralizing avoids behavioral drift when tuning debounce behavior later.

♻️ Suggested direction
-const WS_DEBOUNCE_MS = 300
+import { WS_DEBOUNCE_MS, resetDebounceTimer } from '@/hooks/wsDebounce'

-          if (wsDebounceRef.current) clearTimeout(wsDebounceRef.current)
-          wsDebounceRef.current = setTimeout(() => {
-            useAgentsStore.getState().fetchAgents()
-          }, WS_DEBOUNCE_MS)
+          wsDebounceRef.current = resetDebounceTimer(wsDebounceRef.current, () => {
+            useAgentsStore.getState().fetchAgents()
+          }, WS_DEBOUNCE_MS)

Also applies to: 54-58, 65-68

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

In `@web/src/hooks/useAgentsData.ts` around lines 9 - 10, WS_DEBOUNCE_MS and the
timeout reset logic are duplicated between useAgentsData.ts and
useAgentDetailData.ts; extract a single shared helper (e.g., createWsDebounce or
a constant and a resetDebounce function) into a new module and import it from
both hooks so both use the same debounce value and reset behavior. Update
references to WS_DEBOUNCE_MS in useAgentsData.ts and useAgentDetailData.ts to
import the constant, move any timeout/reset logic into the shared helper
(referencing the same function name like resetWsDebounce or useWsDebounce) and
replace the local implementations in both hooks to call the shared utility.
web/src/__tests__/hooks/useAgentDetailData.test.ts (1)

179-259: 🧹 Nitpick | 🔵 Trivial

Add agentName transition tests for handler setup/teardown.

Please add rerender cases for '' → 'alice' and 'alice' → '' to validate debounce handler lifecycle across route-param transitions, not only steady state.

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

In `@web/src/__tests__/hooks/useAgentDetailData.test.ts` around lines 179 - 259,
Add two tests that exercise agentName transitions for useAgentDetailData: (1)
initial '' -> 'alice' should set up a new debounce handler when rerendered to
'alice' and trigger fetchAgentDetail after 300ms when its handler is invoked;
(2) initial 'alice' -> '' should tear down the debounce handler so invoking the
previous handler after rerender/unmount does not call fetchAgentDetail.
Implement each by using renderHook(({ name }) => useAgentDetailData(name), {
initialProps: '<start>' }) and then rerender({ name: '<end>' }); capture
handlers from vi.mocked(useWebSocket).mock.calls after each render/rerender,
call the appropriate handler(s), use vi.advanceTimersByTime to assert debounce
behavior (no immediate call, single call after 300ms), and assert timeouts are
cleared when transitioning away or unmounting (mockFetchAgentDetail remains not
called).
web/src/pages/org/DepartmentStatsBar.tsx (1)

17-26: ⚠️ Potential issue | 🟠 Major

Do not default missing currency to 'EUR' when rendering cost.

Line [17] can silently mislabel monetary values. Require a real currency for Line [25], otherwise skip the cost pill.

💡 Proposed fix
 interface DepartmentStatsBarProps {
   agentCount: number
   activeCount: number
   cost7d: number | null
-  currency?: string
+  currency?: string | null
   className?: string
 }
@@
 export function DepartmentStatsBar({
   agentCount,
   activeCount,
   cost7d,
-  currency = 'EUR',
+  currency,
   className,
 }: DepartmentStatsBarProps) {
@@
-      {cost7d !== null && Number.isFinite(cost7d) && (
+      {cost7d !== null && Number.isFinite(cost7d) && currency && (
         <StatPill label="Cost (7d)" value={formatCurrency(cost7d, currency)} />
       )}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/pages/org/DepartmentStatsBar.tsx` around lines 17 - 26, The component
currently defaults currency to 'EUR' which can silently mislabel amounts; remove
the defaulting in the DepartmentStatsBar parameter (don't set currency = 'EUR')
and update the cost pill render condition to only show when cost7d is not null,
Number.isFinite(cost7d) is true, and a real currency is provided (e.g. currency
!= null && currency !== ''). Adjust the DepartmentStatsBarProps type if
necessary so callers must supply currency when they want a cost shown, and keep
using StatPill and formatCurrency(cost7d, currency) unchanged when the currency
is present.
web/src/pages/org-edit/AgentEditDrawer.tsx (1)

69-71: ⚠️ Potential issue | 🟡 Minor

Parse hiring_date safely for date-only values.

Line [69] uses new Date(agent.hiring_date), which can shift YYYY-MM-DD by timezone and produce incorrect day in US locales. Also, Line [70] should depend on agent?.hiring_date rather than the full agent object.

🛡️ Proposed fix
-  const hiredDate = useMemo(
-    () => agent?.hiring_date ? new Date(agent.hiring_date).toLocaleDateString() : '',
-    [agent],
-  )
+  const hiredDate = useMemo(() => {
+    if (!agent?.hiring_date) return ''
+    const raw = agent.hiring_date
+    const dateOnly = /^(\d{4})-(\d{2})-(\d{2})$/.exec(raw)
+    const parsed = dateOnly
+      ? new Date(Number(dateOnly[1]), Number(dateOnly[2]) - 1, Number(dateOnly[3]))
+      : new Date(raw)
+    return Number.isNaN(parsed.getTime()) ? '' : parsed.toLocaleDateString()
+  }, [agent?.hiring_date])
#!/bin/bash
# Verify current hiring_date parsing and memo dependencies
rg -n -C2 "new Date\(agent\.hiring_date\)|const hiredDate = useMemo|\[agent\]" web/src/pages/org-edit/AgentEditDrawer.tsx
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/pages/org-edit/AgentEditDrawer.tsx` around lines 69 - 71, The current
useMemo that formats the hiring date uses new Date(agent.hiring_date) which can
shift YYYY-MM-DD across timezones and also depends on the whole agent object;
update the memo to depend on agent?.hiring_date and parse the string as a
date-only value (e.g., split "YYYY-MM-DD" into year/month/day and construct a
UTC/local date without time) before calling toLocaleDateString() so the
displayed day never shifts across timezones; reference the existing useMemo
block that formats agent.hiring_date and the toLocaleDateString() call to locate
where to change the parsing and the dependency array.
web/src/__tests__/pages/org/build-org-tree.test.ts (1)

337-340: ⚠️ Potential issue | 🟡 Minor

Remove the undefined as unknown as string escape hatch.

This cast bypasses the optional AgentConfig.id behavior the test is supposed to cover. If the helper ever starts supplying a default id again, this test can keep compiling while no longer exercising the missing-id path. Make the helper accept id?: string and pass undefined (or omit the field) here.

💡 Keep the fixture type-safe
-function makeAgent(overrides: Partial<AgentConfig> & { id: string; name: string }): AgentConfig {
+function makeAgent(overrides: Partial<AgentConfig> & { name: string; id?: string }): AgentConfig {
-      makeAgent({ id: undefined as unknown as string, name: 'NoIdAgent', department: 'engineering', level: 'mid' }),
+      makeAgent({ id: undefined, name: 'NoIdAgent', department: 'engineering', level: 'mid' }),
🤖 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 337 - 340,
Update the test fixture and helper so the test truly exercises a missing id:
change the makeAgent helper signature to accept id?: string (make AgentConfig.id
optional) and in the test "uses agent.name as node id when agent.id is
undefined" pass undefined directly or omit the id field instead of using the
cast `undefined as unknown as string`; update references to makeAgent and any
types (e.g., AgentConfig) to reflect optional id so the test compiles and
correctly covers the missing-id path.
web/src/pages/org/build-org-tree.ts (1)

97-98: ⚠️ Potential issue | 🟠 Major

agent.name is still not a safe surrogate key here.

id is now optional, so every id ?? name fallback in this graph builder treats names as globally unique. Two missing-id agents with the same name will collide in teamMemberSet, node ids, edge ids, runtime-status lookups, and CEO/head exclusion, which can merge nodes or wire edges to the wrong person. Generate one deterministic unique key per agent and reuse it everywhere instead of falling back to agent.name.

Also applies to: 126-129, 136-152, 161-197, 237-239

🤖 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 97 - 98, The code
improperly treats agent.name as a surrogate key whenever agent.id is missing
(seen around resolveRuntimeStatus usage and in teamMemberSet, node id/edge id
generation, runtime-status lookups, and CEO/head exclusion), causing collisions
for multiple agents with the same name; fix by computing a deterministic unique
key for each agent (e.g., a stable concat/hash of available unique fields such
as name + email/role + array index) once when building the graph and reuse that
key everywhere instead of using id ?? name — update the places referencing id ??
name (including resolveRuntimeStatus calls, teamMemberSet population, node/edge
id creation, runtime-status map lookups, and CEO/head exclusion logic) to use
the new agentKey value so all lookups and sets remain consistent and
collision-free.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/design/brand-and-ux.md`:
- Line 203: Update the docs for DeptHealthBar in dept-health-bar.tsx: replace
the phrase "utilization percentage (null-safe -- shows N/A when health
unavailable)" with wording that uses "utilization unavailable" to match the API
semantics (for example: "utilization (null-safe — shows N/A when utilization
unavailable)"). Keep the rest of the description (animated horizontal fill,
color auto-mapped via getHealthColor()) unchanged.

---

Outside diff comments:
In `@web/src/pages/agents/AgentGridView.stories.tsx`:
- Around line 49-61: The story meta for AgentGridView is missing the
accessibility testing parameter; update the meta object (the const meta that
satisfies Meta<typeof AgentGridView>) to include parameters: { a11y: { test:
'error' } } so the story enables the same a11y testing as other stories in the
PR.

In `@web/src/pages/org-edit/AgentEditDrawer.tsx`:
- Around line 48-62: The state-sync block that compares agent to
prevAgentRef.current and calls setForm, setSubmitError, setDeleteOpen, and
setDeleting should be moved out of render into a useEffect that depends on
agent; create a useEffect(() => { ... }, [agent]) which performs the same logic
(update prevAgentRef.current, call setForm with agent fields,
setSubmitError(null), setDeleteOpen(false), setDeleting(false)) and remove the
inline state updates from the render path so only pure reads occur during render
and all side-effects run inside the useEffect.

---

Duplicate comments:
In `@web/src/__tests__/hooks/useAgentDetailData.test.ts`:
- Around line 179-259: Add two tests that exercise agentName transitions for
useAgentDetailData: (1) initial '' -> 'alice' should set up a new debounce
handler when rerendered to 'alice' and trigger fetchAgentDetail after 300ms when
its handler is invoked; (2) initial 'alice' -> '' should tear down the debounce
handler so invoking the previous handler after rerender/unmount does not call
fetchAgentDetail. Implement each by using renderHook(({ name }) =>
useAgentDetailData(name), { initialProps: '<start>' }) and then rerender({ name:
'<end>' }); capture handlers from vi.mocked(useWebSocket).mock.calls after each
render/rerender, call the appropriate handler(s), use vi.advanceTimersByTime to
assert debounce behavior (no immediate call, single call after 300ms), and
assert timeouts are cleared when transitioning away or unmounting
(mockFetchAgentDetail remains not called).

In `@web/src/__tests__/pages/org/build-org-tree.test.ts`:
- Around line 337-340: Update the test fixture and helper so the test truly
exercises a missing id: change the makeAgent helper signature to accept id?:
string (make AgentConfig.id optional) and in the test "uses agent.name as node
id when agent.id is undefined" pass undefined directly or omit the id field
instead of using the cast `undefined as unknown as string`; update references to
makeAgent and any types (e.g., AgentConfig) to reflect optional id so the test
compiles and correctly covers the missing-id path.

In `@web/src/hooks/useAgentsData.ts`:
- Around line 9-10: WS_DEBOUNCE_MS and the timeout reset logic are duplicated
between useAgentsData.ts and useAgentDetailData.ts; extract a single shared
helper (e.g., createWsDebounce or a constant and a resetDebounce function) into
a new module and import it from both hooks so both use the same debounce value
and reset behavior. Update references to WS_DEBOUNCE_MS in useAgentsData.ts and
useAgentDetailData.ts to import the constant, move any timeout/reset logic into
the shared helper (referencing the same function name like resetWsDebounce or
useWsDebounce) and replace the local implementations in both hooks to call the
shared utility.

In `@web/src/pages/org-edit/AgentEditDrawer.tsx`:
- Around line 69-71: The current useMemo that formats the hiring date uses new
Date(agent.hiring_date) which can shift YYYY-MM-DD across timezones and also
depends on the whole agent object; update the memo to depend on
agent?.hiring_date and parse the string as a date-only value (e.g., split
"YYYY-MM-DD" into year/month/day and construct a UTC/local date without time)
before calling toLocaleDateString() so the displayed day never shifts across
timezones; reference the existing useMemo block that formats agent.hiring_date
and the toLocaleDateString() call to locate where to change the parsing and the
dependency array.

In `@web/src/pages/org/build-org-tree.ts`:
- Around line 97-98: The code improperly treats agent.name as a surrogate key
whenever agent.id is missing (seen around resolveRuntimeStatus usage and in
teamMemberSet, node id/edge id generation, runtime-status lookups, and CEO/head
exclusion), causing collisions for multiple agents with the same name; fix by
computing a deterministic unique key for each agent (e.g., a stable concat/hash
of available unique fields such as name + email/role + array index) once when
building the graph and reuse that key everywhere instead of using id ?? name —
update the places referencing id ?? name (including resolveRuntimeStatus calls,
teamMemberSet population, node/edge id creation, runtime-status map lookups, and
CEO/head exclusion logic) to use the new agentKey value so all lookups and sets
remain consistent and collision-free.

In `@web/src/pages/org/DepartmentStatsBar.tsx`:
- Around line 17-26: The component currently defaults currency to 'EUR' which
can silently mislabel amounts; remove the defaulting in the DepartmentStatsBar
parameter (don't set currency = 'EUR') and update the cost pill render condition
to only show when cost7d is not null, Number.isFinite(cost7d) is true, and a
real currency is provided (e.g. currency != null && currency !== ''). Adjust the
DepartmentStatsBarProps type if necessary so callers must supply currency when
they want a cost shown, and keep using StatPill and formatCurrency(cost7d,
currency) unchanged when the currency is present.
🪄 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: 96eb691f-b153-4de0-95ed-3ef1942be427

📥 Commits

Reviewing files that changed from the base of the PR and between 8d5a59a and df79937.

📒 Files selected for processing (52)
  • CLAUDE.md
  • docs/design/brand-and-ux.md
  • web/src/__tests__/components/ui/dept-health-bar.test.tsx
  • web/src/__tests__/helpers/factories.ts
  • web/src/__tests__/hooks/useAgentDetailData.test.ts
  • web/src/__tests__/hooks/useAgentsData.test.ts
  • web/src/__tests__/pages/dashboard/OrgHealthSection.test.tsx
  • web/src/__tests__/pages/org-edit/DepartmentsTab.test.tsx
  • web/src/__tests__/pages/org/DepartmentStatsBar.test.tsx
  • web/src/__tests__/pages/org/build-org-tree.test.ts
  • web/src/__tests__/stores/agents.test.ts
  • web/src/__tests__/stores/analytics.test.ts
  • web/src/__tests__/stores/budget.test.ts
  • web/src/__tests__/stores/company.test.ts
  • web/src/__tests__/utils/agents.property.test.ts
  • web/src/__tests__/utils/agents.test.ts
  • web/src/__tests__/utils/dashboard.property.test.ts
  • web/src/__tests__/utils/dashboard.test.ts
  • web/src/api/types.ts
  • web/src/components/ui/dept-health-bar.stories.tsx
  • web/src/components/ui/dept-health-bar.tsx
  • web/src/hooks/useAgentDetailData.ts
  • web/src/hooks/useAgentsData.ts
  • web/src/pages/AgentDetailPage.tsx
  • web/src/pages/DashboardPage.tsx
  • web/src/pages/agents/AgentGridView.stories.tsx
  • web/src/pages/agents/AgentGridView.tsx
  • web/src/pages/agents/AgentIdentityHeader.stories.tsx
  • web/src/pages/agents/AgentIdentityHeader.tsx
  • web/src/pages/dashboard/DashboardPage.stories.tsx
  • web/src/pages/dashboard/OrgHealthSection.stories.tsx
  • web/src/pages/dashboard/OrgHealthSection.tsx
  • web/src/pages/org-edit/AgentCreateDialog.stories.tsx
  • web/src/pages/org-edit/AgentEditDrawer.stories.tsx
  • web/src/pages/org-edit/AgentEditDrawer.tsx
  • web/src/pages/org-edit/AgentsTab.stories.tsx
  • web/src/pages/org-edit/AgentsTab.tsx
  • web/src/pages/org-edit/DepartmentEditDrawer.stories.tsx
  • web/src/pages/org-edit/DepartmentEditDrawer.tsx
  • web/src/pages/org-edit/DepartmentsTab.stories.tsx
  • web/src/pages/org-edit/DepartmentsTab.tsx
  • web/src/pages/org-edit/YamlEditorPanel.stories.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/build-org-tree.ts
  • web/src/pages/setup/ThemePreview.tsx
  • web/src/stores/budget.ts
  • web/src/stores/company.ts
  • web/src/utils/agents.ts
  • web/src/utils/dashboard.ts
💤 Files with no reviewable changes (1)
  • web/src/pages/DashboardPage.tsx
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: Dashboard Test
  • GitHub Check: Build Sandbox
  • GitHub Check: Build Web
  • GitHub Check: Build Backend
  • GitHub Check: Dependency Review
  • GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (9)
web/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

web/src/**/*.{ts,tsx}: Web Dashboard: ALWAYS reuse existing components from web/src/components/ui/ before creating new ones. Reuse StatusBadge, MetricCard, Sparkline, SectionCard, AgentCard, DeptHealthBar, ProgressGauge, StatPill, Avatar, Button, Toast, Skeleton variants, EmptyState, ErrorBoundary, ConfirmDialog, CommandPalette, InlineEdit, AnimatedPresence, StaggerGroup, Drawer, InputField, SelectField, SliderField, ToggleField, TaskStatusIndicator, PriorityBadge, ProviderHealthBadge, TokenUsageBar, CodeMirrorEditor, SegmentedControl, ThemeToggle.
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 text-metric font-bold—use <MetricCard>. Do NOT render initials circles manually—use <Avatar>. Do NOT create complex (>8 line) JSX inside .map()—extract to a shared component.
Web design system enforcement: A PostToolUse hook (scripts/check_web_design_system.py) runs automatically on every Edit/Write to web/src/ files. It catches hardcoded hex colors, rgba values, font-family declarations, missing Storybook stories, duplicate patterns, and complex map blocks. Fix all violations before proceeding.
React 19 + shadcn/ui + Tailwind CSS 4 dashboard: Use React Router, Zustand stores, @tanstack/react-query, @xyflow/react, @dagrejs/dagre, d3-force, @dnd-kit, Recharts, Framer Motion, cmdk, js-yaml, Axios.

Files:

  • web/src/__tests__/stores/agents.test.ts
  • web/src/pages/org-edit/DepartmentEditDrawer.tsx
  • web/src/components/ui/dept-health-bar.stories.tsx
  • web/src/pages/agents/AgentIdentityHeader.tsx
  • web/src/pages/agents/AgentIdentityHeader.stories.tsx
  • web/src/pages/org-edit/YamlEditorPanel.stories.tsx
  • web/src/__tests__/pages/org-edit/DepartmentsTab.test.tsx
  • web/src/pages/org-edit/AgentEditDrawer.stories.tsx
  • web/src/pages/org-edit/AgentCreateDialog.stories.tsx
  • web/src/stores/budget.ts
  • web/src/pages/agents/AgentGridView.tsx
  • web/src/pages/AgentDetailPage.tsx
  • web/src/pages/org-edit/AgentsTab.stories.tsx
  • web/src/pages/org/DepartmentGroupNode.stories.tsx
  • web/src/pages/setup/ThemePreview.tsx
  • web/src/pages/org-edit/DepartmentsTab.tsx
  • web/src/pages/dashboard/DashboardPage.stories.tsx
  • web/src/utils/agents.ts
  • web/src/utils/dashboard.ts
  • web/src/hooks/useAgentsData.ts
  • web/src/__tests__/components/ui/dept-health-bar.test.tsx
  • web/src/pages/org-edit/DepartmentsTab.stories.tsx
  • web/src/__tests__/utils/agents.property.test.ts
  • web/src/pages/dashboard/OrgHealthSection.stories.tsx
  • web/src/pages/agents/AgentGridView.stories.tsx
  • web/src/__tests__/utils/dashboard.test.ts
  • web/src/__tests__/pages/dashboard/OrgHealthSection.test.tsx
  • web/src/pages/org/DepartmentGroupNode.tsx
  • web/src/components/ui/dept-health-bar.tsx
  • web/src/__tests__/hooks/useAgentDetailData.test.ts
  • web/src/__tests__/utils/agents.test.ts
  • web/src/pages/org-edit/AgentEditDrawer.tsx
  • web/src/hooks/useAgentDetailData.ts
  • web/src/pages/org/DepartmentStatsBar.tsx
  • web/src/pages/org/DepartmentStatsBar.stories.tsx
  • web/src/stores/company.ts
  • web/src/__tests__/utils/dashboard.property.test.ts
  • web/src/api/types.ts
  • web/src/__tests__/pages/org/build-org-tree.test.ts
  • web/src/pages/org/build-org-tree.ts
  • web/src/pages/dashboard/OrgHealthSection.tsx
  • web/src/__tests__/stores/analytics.test.ts
  • web/src/pages/org-edit/DepartmentEditDrawer.stories.tsx
  • web/src/__tests__/pages/org/DepartmentStatsBar.test.tsx
  • web/src/__tests__/hooks/useAgentsData.test.ts
  • web/src/__tests__/stores/budget.test.ts
  • web/src/__tests__/helpers/factories.ts
  • web/src/pages/org-edit/AgentsTab.tsx
  • web/src/__tests__/stores/company.test.ts
web/src/**/*.{ts,tsx,css}

📄 CodeRabbit inference engine (CLAUDE.md)

Design tokens: Colors use Tailwind semantic classes (text-foreground, bg-card, text-accent, etc.) or CSS variables (var(--so-accent)). NEVER hardcode hex values. Typography uses font-sans or font-mono. Spacing uses density-aware tokens or standard Tailwind. Shadows/borders use token variables.

Files:

  • web/src/__tests__/stores/agents.test.ts
  • web/src/pages/org-edit/DepartmentEditDrawer.tsx
  • web/src/components/ui/dept-health-bar.stories.tsx
  • web/src/pages/agents/AgentIdentityHeader.tsx
  • web/src/pages/agents/AgentIdentityHeader.stories.tsx
  • web/src/pages/org-edit/YamlEditorPanel.stories.tsx
  • web/src/__tests__/pages/org-edit/DepartmentsTab.test.tsx
  • web/src/pages/org-edit/AgentEditDrawer.stories.tsx
  • web/src/pages/org-edit/AgentCreateDialog.stories.tsx
  • web/src/stores/budget.ts
  • web/src/pages/agents/AgentGridView.tsx
  • web/src/pages/AgentDetailPage.tsx
  • web/src/pages/org-edit/AgentsTab.stories.tsx
  • web/src/pages/org/DepartmentGroupNode.stories.tsx
  • web/src/pages/setup/ThemePreview.tsx
  • web/src/pages/org-edit/DepartmentsTab.tsx
  • web/src/pages/dashboard/DashboardPage.stories.tsx
  • web/src/utils/agents.ts
  • web/src/utils/dashboard.ts
  • web/src/hooks/useAgentsData.ts
  • web/src/__tests__/components/ui/dept-health-bar.test.tsx
  • web/src/pages/org-edit/DepartmentsTab.stories.tsx
  • web/src/__tests__/utils/agents.property.test.ts
  • web/src/pages/dashboard/OrgHealthSection.stories.tsx
  • web/src/pages/agents/AgentGridView.stories.tsx
  • web/src/__tests__/utils/dashboard.test.ts
  • web/src/__tests__/pages/dashboard/OrgHealthSection.test.tsx
  • web/src/pages/org/DepartmentGroupNode.tsx
  • web/src/components/ui/dept-health-bar.tsx
  • web/src/__tests__/hooks/useAgentDetailData.test.ts
  • web/src/__tests__/utils/agents.test.ts
  • web/src/pages/org-edit/AgentEditDrawer.tsx
  • web/src/hooks/useAgentDetailData.ts
  • web/src/pages/org/DepartmentStatsBar.tsx
  • web/src/pages/org/DepartmentStatsBar.stories.tsx
  • web/src/stores/company.ts
  • web/src/__tests__/utils/dashboard.property.test.ts
  • web/src/api/types.ts
  • web/src/__tests__/pages/org/build-org-tree.test.ts
  • web/src/pages/org/build-org-tree.ts
  • web/src/pages/dashboard/OrgHealthSection.tsx
  • web/src/__tests__/stores/analytics.test.ts
  • web/src/pages/org-edit/DepartmentEditDrawer.stories.tsx
  • web/src/__tests__/pages/org/DepartmentStatsBar.test.tsx
  • web/src/__tests__/hooks/useAgentsData.test.ts
  • web/src/__tests__/stores/budget.test.ts
  • web/src/__tests__/helpers/factories.ts
  • web/src/pages/org-edit/AgentsTab.tsx
  • web/src/__tests__/stores/company.test.ts
**/*.{ts,tsx,json}

📄 CodeRabbit inference engine (CLAUDE.md)

TypeScript 6.0: Remove baseUrl (deprecated); paths entries are relative to tsconfig directory. esModuleInterop always true—cannot be set to false. types defaults to []—must explicitly list (e.g. 'types': ['vitest/globals']). DOM.Iterable merged into DOM. moduleResolution: 'classic' and 'node10' removed—use 'bundler' or 'nodenext'. strict defaults to true. noUncheckedSideEffectImports defaults to true.

Files:

  • web/src/__tests__/stores/agents.test.ts
  • web/src/pages/org-edit/DepartmentEditDrawer.tsx
  • web/src/components/ui/dept-health-bar.stories.tsx
  • web/src/pages/agents/AgentIdentityHeader.tsx
  • web/src/pages/agents/AgentIdentityHeader.stories.tsx
  • web/src/pages/org-edit/YamlEditorPanel.stories.tsx
  • web/src/__tests__/pages/org-edit/DepartmentsTab.test.tsx
  • web/src/pages/org-edit/AgentEditDrawer.stories.tsx
  • web/src/pages/org-edit/AgentCreateDialog.stories.tsx
  • web/src/stores/budget.ts
  • web/src/pages/agents/AgentGridView.tsx
  • web/src/pages/AgentDetailPage.tsx
  • web/src/pages/org-edit/AgentsTab.stories.tsx
  • web/src/pages/org/DepartmentGroupNode.stories.tsx
  • web/src/pages/setup/ThemePreview.tsx
  • web/src/pages/org-edit/DepartmentsTab.tsx
  • web/src/pages/dashboard/DashboardPage.stories.tsx
  • web/src/utils/agents.ts
  • web/src/utils/dashboard.ts
  • web/src/hooks/useAgentsData.ts
  • web/src/__tests__/components/ui/dept-health-bar.test.tsx
  • web/src/pages/org-edit/DepartmentsTab.stories.tsx
  • web/src/__tests__/utils/agents.property.test.ts
  • web/src/pages/dashboard/OrgHealthSection.stories.tsx
  • web/src/pages/agents/AgentGridView.stories.tsx
  • web/src/__tests__/utils/dashboard.test.ts
  • web/src/__tests__/pages/dashboard/OrgHealthSection.test.tsx
  • web/src/pages/org/DepartmentGroupNode.tsx
  • web/src/components/ui/dept-health-bar.tsx
  • web/src/__tests__/hooks/useAgentDetailData.test.ts
  • web/src/__tests__/utils/agents.test.ts
  • web/src/pages/org-edit/AgentEditDrawer.tsx
  • web/src/hooks/useAgentDetailData.ts
  • web/src/pages/org/DepartmentStatsBar.tsx
  • web/src/pages/org/DepartmentStatsBar.stories.tsx
  • web/src/stores/company.ts
  • web/src/__tests__/utils/dashboard.property.test.ts
  • web/src/api/types.ts
  • web/src/__tests__/pages/org/build-org-tree.test.ts
  • web/src/pages/org/build-org-tree.ts
  • web/src/pages/dashboard/OrgHealthSection.tsx
  • web/src/__tests__/stores/analytics.test.ts
  • web/src/pages/org-edit/DepartmentEditDrawer.stories.tsx
  • web/src/__tests__/pages/org/DepartmentStatsBar.test.tsx
  • web/src/__tests__/hooks/useAgentsData.test.ts
  • web/src/__tests__/stores/budget.test.ts
  • web/src/__tests__/helpers/factories.ts
  • web/src/pages/org-edit/AgentsTab.tsx
  • web/src/__tests__/stores/company.test.ts
**/*.{py,ts,tsx,go}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{py,ts,tsx,go}: Lint & format: Python via ruff (uv run ruff check + uv run ruff format). TypeScript web via ESLint (zero warnings enforced: npm --prefix web run lint). Go CLI via golangci-lint and go vet. All enforced in pre-commit hooks.
Type checking: Python via mypy strict mode (uv run mypy src/ tests/). TypeScript via npm --prefix web run type-check. Go via go -C cli vet ./....

Files:

  • web/src/__tests__/stores/agents.test.ts
  • web/src/pages/org-edit/DepartmentEditDrawer.tsx
  • web/src/components/ui/dept-health-bar.stories.tsx
  • web/src/pages/agents/AgentIdentityHeader.tsx
  • web/src/pages/agents/AgentIdentityHeader.stories.tsx
  • web/src/pages/org-edit/YamlEditorPanel.stories.tsx
  • web/src/__tests__/pages/org-edit/DepartmentsTab.test.tsx
  • web/src/pages/org-edit/AgentEditDrawer.stories.tsx
  • web/src/pages/org-edit/AgentCreateDialog.stories.tsx
  • web/src/stores/budget.ts
  • web/src/pages/agents/AgentGridView.tsx
  • web/src/pages/AgentDetailPage.tsx
  • web/src/pages/org-edit/AgentsTab.stories.tsx
  • web/src/pages/org/DepartmentGroupNode.stories.tsx
  • web/src/pages/setup/ThemePreview.tsx
  • web/src/pages/org-edit/DepartmentsTab.tsx
  • web/src/pages/dashboard/DashboardPage.stories.tsx
  • web/src/utils/agents.ts
  • web/src/utils/dashboard.ts
  • web/src/hooks/useAgentsData.ts
  • web/src/__tests__/components/ui/dept-health-bar.test.tsx
  • web/src/pages/org-edit/DepartmentsTab.stories.tsx
  • web/src/__tests__/utils/agents.property.test.ts
  • web/src/pages/dashboard/OrgHealthSection.stories.tsx
  • web/src/pages/agents/AgentGridView.stories.tsx
  • web/src/__tests__/utils/dashboard.test.ts
  • web/src/__tests__/pages/dashboard/OrgHealthSection.test.tsx
  • web/src/pages/org/DepartmentGroupNode.tsx
  • web/src/components/ui/dept-health-bar.tsx
  • web/src/__tests__/hooks/useAgentDetailData.test.ts
  • web/src/__tests__/utils/agents.test.ts
  • web/src/pages/org-edit/AgentEditDrawer.tsx
  • web/src/hooks/useAgentDetailData.ts
  • web/src/pages/org/DepartmentStatsBar.tsx
  • web/src/pages/org/DepartmentStatsBar.stories.tsx
  • web/src/stores/company.ts
  • web/src/__tests__/utils/dashboard.property.test.ts
  • web/src/api/types.ts
  • web/src/__tests__/pages/org/build-org-tree.test.ts
  • web/src/pages/org/build-org-tree.ts
  • web/src/pages/dashboard/OrgHealthSection.tsx
  • web/src/__tests__/stores/analytics.test.ts
  • web/src/pages/org-edit/DepartmentEditDrawer.stories.tsx
  • web/src/__tests__/pages/org/DepartmentStatsBar.test.tsx
  • web/src/__tests__/hooks/useAgentsData.test.ts
  • web/src/__tests__/stores/budget.test.ts
  • web/src/__tests__/helpers/factories.ts
  • web/src/pages/org-edit/AgentsTab.tsx
  • web/src/__tests__/stores/company.test.ts
web/src/pages/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Web dashboard pages: Lazy-loaded page components (one per route). Page-scoped sub-components in pages/<page-name>/ subdirs. Feature dirs added as pages are built. Stores for auth, WebSocket, toast, analytics, setup wizard, company, agents, budget, tasks, settings, providers, theme.

Files:

  • web/src/pages/org-edit/DepartmentEditDrawer.tsx
  • web/src/pages/agents/AgentIdentityHeader.tsx
  • web/src/pages/agents/AgentIdentityHeader.stories.tsx
  • web/src/pages/org-edit/YamlEditorPanel.stories.tsx
  • web/src/pages/org-edit/AgentEditDrawer.stories.tsx
  • web/src/pages/org-edit/AgentCreateDialog.stories.tsx
  • web/src/pages/agents/AgentGridView.tsx
  • web/src/pages/AgentDetailPage.tsx
  • web/src/pages/org-edit/AgentsTab.stories.tsx
  • web/src/pages/org/DepartmentGroupNode.stories.tsx
  • web/src/pages/setup/ThemePreview.tsx
  • web/src/pages/org-edit/DepartmentsTab.tsx
  • web/src/pages/dashboard/DashboardPage.stories.tsx
  • web/src/pages/org-edit/DepartmentsTab.stories.tsx
  • web/src/pages/dashboard/OrgHealthSection.stories.tsx
  • web/src/pages/agents/AgentGridView.stories.tsx
  • web/src/pages/org/DepartmentGroupNode.tsx
  • web/src/pages/org-edit/AgentEditDrawer.tsx
  • web/src/pages/org/DepartmentStatsBar.tsx
  • web/src/pages/org/DepartmentStatsBar.stories.tsx
  • web/src/pages/org/build-org-tree.ts
  • web/src/pages/dashboard/OrgHealthSection.tsx
  • web/src/pages/org-edit/DepartmentEditDrawer.stories.tsx
  • web/src/pages/org-edit/AgentsTab.tsx
web/src/components/ui/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Web components: Place new shared components in web/src/components/ui/ with kebab-case filenames. Create .stories.tsx with all states. Export props as TypeScript interface. Use design tokens exclusively—no hardcoded colors, fonts, or spacing. Import cn from @/lib/utils for conditional class merging.

Files:

  • web/src/components/ui/dept-health-bar.stories.tsx
  • web/src/components/ui/dept-health-bar.tsx
web/**/*.stories.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Storybook 10: ESM-only—no CJS support. Packages like @storybook/addon-essentials, @storybook/addon-interactions, @storybook/test, @storybook/blocks no longer published. @storybook/addon-docs is separate. Import from storybook/test (not @storybook/test), storybook/actions. Use defineMain from @storybook/react-vite/node and definePreview from @storybook/react-vite. Backgrounds API: use parameters.backgrounds.options (object) + initialGlobals.backgrounds.value. a11y testing: use parameters.a11y.test: 'error' | 'todo' | 'off'. Minimum versions: Node 20.19+, Vite 5+, Vitest 3+, TypeScript 4.9+.

Files:

  • web/src/components/ui/dept-health-bar.stories.tsx
  • web/src/pages/agents/AgentIdentityHeader.stories.tsx
  • web/src/pages/org-edit/YamlEditorPanel.stories.tsx
  • web/src/pages/org-edit/AgentEditDrawer.stories.tsx
  • web/src/pages/org-edit/AgentCreateDialog.stories.tsx
  • web/src/pages/org-edit/AgentsTab.stories.tsx
  • web/src/pages/org/DepartmentGroupNode.stories.tsx
  • web/src/pages/dashboard/DashboardPage.stories.tsx
  • web/src/pages/org-edit/DepartmentsTab.stories.tsx
  • web/src/pages/dashboard/OrgHealthSection.stories.tsx
  • web/src/pages/agents/AgentGridView.stories.tsx
  • web/src/pages/org/DepartmentStatsBar.stories.tsx
  • web/src/pages/org-edit/DepartmentEditDrawer.stories.tsx
docs/design/*.md

📄 CodeRabbit inference engine (CLAUDE.md)

When approved deviations occur, update the relevant docs/design/ page to reflect the new reality.

Files:

  • docs/design/brand-and-ux.md
docs/**/*.md

📄 CodeRabbit inference engine (CLAUDE.md)

Documentation: docs/ (Markdown, built with Zensical, config: mkdocs.yml). Design spec in docs/design/ (11 pages), architecture in docs/architecture/, roadmap in docs/roadmap/. REST API reference auto-generated by scripts/export_openapi.py. Library reference auto-generated via mkdocstrings + Griffe. Landing page in site/ (Astro).

Files:

  • docs/design/brand-and-ux.md
🧠 Learnings (12)
📓 Common learnings
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-29T11:41:44.483Z
Learning: Applies to web/src/**/*.{ts,tsx} : Web Dashboard: ALWAYS reuse existing components from `web/src/components/ui/` before creating new ones. Reuse StatusBadge, MetricCard, Sparkline, SectionCard, AgentCard, DeptHealthBar, ProgressGauge, StatPill, Avatar, Button, Toast, Skeleton variants, EmptyState, ErrorBoundary, ConfirmDialog, CommandPalette, InlineEdit, AnimatedPresence, StaggerGroup, Drawer, InputField, SelectField, SliderField, ToggleField, TaskStatusIndicator, PriorityBadge, ProviderHealthBadge, TokenUsageBar, CodeMirrorEditor, SegmentedControl, ThemeToggle.
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-29T11:41:44.483Z
Learning: Applies to web/src/**/*.{ts,tsx} : React 19 + shadcn/ui + Tailwind CSS 4 dashboard: Use React Router, Zustand stores, tanstack/react-query, xyflow/react, dagrejs/dagre, d3-force, dnd-kit, Recharts, Framer Motion, cmdk, js-yaml, Axios.
📚 Learning: 2026-03-29T11:41:44.483Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-29T11:41:44.483Z
Learning: Applies to web/src/**/*.{ts,tsx} : Web Dashboard: ALWAYS reuse existing components from `web/src/components/ui/` before creating new ones. Reuse StatusBadge, MetricCard, Sparkline, SectionCard, AgentCard, DeptHealthBar, ProgressGauge, StatPill, Avatar, Button, Toast, Skeleton variants, EmptyState, ErrorBoundary, ConfirmDialog, CommandPalette, InlineEdit, AnimatedPresence, StaggerGroup, Drawer, InputField, SelectField, SliderField, ToggleField, TaskStatusIndicator, PriorityBadge, ProviderHealthBadge, TokenUsageBar, CodeMirrorEditor, SegmentedControl, ThemeToggle.

Applied to files:

  • web/src/pages/org-edit/DepartmentEditDrawer.tsx
  • web/src/components/ui/dept-health-bar.stories.tsx
  • CLAUDE.md
  • web/src/__tests__/pages/org-edit/DepartmentsTab.test.tsx
  • web/src/pages/AgentDetailPage.tsx
  • web/src/pages/setup/ThemePreview.tsx
  • web/src/pages/org-edit/DepartmentsTab.tsx
  • web/src/pages/dashboard/DashboardPage.stories.tsx
  • web/src/utils/dashboard.ts
  • web/src/hooks/useAgentsData.ts
  • web/src/pages/dashboard/OrgHealthSection.stories.tsx
  • web/src/__tests__/utils/dashboard.test.ts
  • web/src/__tests__/pages/dashboard/OrgHealthSection.test.tsx
  • web/src/components/ui/dept-health-bar.tsx
  • web/src/hooks/useAgentDetailData.ts
  • web/src/pages/org/DepartmentStatsBar.tsx
  • docs/design/brand-and-ux.md
  • web/src/pages/dashboard/OrgHealthSection.tsx
📚 Learning: 2026-03-29T11:41:44.483Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-29T11:41:44.483Z
Learning: Applies to web/src/**/*.{ts,tsx} : React 19 + shadcn/ui + Tailwind CSS 4 dashboard: Use React Router, Zustand stores, tanstack/react-query, xyflow/react, dagrejs/dagre, d3-force, dnd-kit, Recharts, Framer Motion, cmdk, js-yaml, Axios.

Applied to files:

  • web/src/pages/org-edit/DepartmentEditDrawer.tsx
  • CLAUDE.md
  • web/src/pages/org-edit/DepartmentsTab.tsx
  • web/src/pages/dashboard/DashboardPage.stories.tsx
  • web/src/hooks/useAgentsData.ts
  • web/src/pages/org/DepartmentGroupNode.tsx
  • web/src/components/ui/dept-health-bar.tsx
  • web/src/hooks/useAgentDetailData.ts
📚 Learning: 2026-03-29T11:41:44.483Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-29T11:41:44.483Z
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 `text-metric font-bold`—use `<MetricCard>`. Do NOT render initials circles manually—use `<Avatar>`. Do NOT create complex (>8 line) JSX inside `.map()`—extract to a shared component.

Applied to files:

  • web/src/pages/org-edit/DepartmentEditDrawer.tsx
  • web/src/components/ui/dept-health-bar.stories.tsx
  • CLAUDE.md
  • web/src/pages/agents/AgentIdentityHeader.tsx
  • web/src/pages/agents/AgentGridView.tsx
  • web/src/pages/AgentDetailPage.tsx
  • web/src/pages/setup/ThemePreview.tsx
  • web/src/pages/org-edit/DepartmentsTab.tsx
  • web/src/__tests__/components/ui/dept-health-bar.test.tsx
  • web/src/components/ui/dept-health-bar.tsx
  • web/src/pages/org-edit/AgentEditDrawer.tsx
  • web/src/pages/org/DepartmentStatsBar.tsx
  • docs/design/brand-and-ux.md
  • web/src/pages/dashboard/OrgHealthSection.tsx
📚 Learning: 2026-03-29T11:41:44.483Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-29T11:41:44.483Z
Learning: Applies to web/**/*.stories.{ts,tsx} : Storybook 10: ESM-only—no CJS support. Packages like `storybook/addon-essentials`, `storybook/addon-interactions`, `storybook/test`, `storybook/blocks` no longer published. `storybook/addon-docs` is separate. Import from `storybook/test` (not `storybook/test`), `storybook/actions`. Use `defineMain` from `storybook/react-vite/node` and `definePreview` from `storybook/react-vite`. Backgrounds API: use `parameters.backgrounds.options` (object) + `initialGlobals.backgrounds.value`. a11y testing: use `parameters.a11y.test: 'error' | 'todo' | 'off'`. Minimum versions: Node 20.19+, Vite 5+, Vitest 3+, TypeScript 4.9+.

Applied to files:

  • web/src/components/ui/dept-health-bar.stories.tsx
  • web/src/pages/org-edit/YamlEditorPanel.stories.tsx
  • web/src/pages/org-edit/AgentEditDrawer.stories.tsx
  • web/src/pages/org-edit/AgentsTab.stories.tsx
  • web/src/pages/org/DepartmentGroupNode.stories.tsx
  • web/src/pages/org-edit/DepartmentsTab.stories.tsx
  • web/src/pages/agents/AgentGridView.stories.tsx
  • web/src/pages/org/DepartmentStatsBar.stories.tsx
📚 Learning: 2026-03-29T11:41:44.483Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-29T11:41:44.483Z
Learning: Applies to web/src/components/ui/**/*.{ts,tsx} : Web components: Place new shared components in `web/src/components/ui/` with kebab-case filenames. Create `.stories.tsx` with all states. Export props as TypeScript interface. Use design tokens exclusively—no hardcoded colors, fonts, or spacing. Import `cn` from `@/lib/utils` for conditional class merging.

Applied to files:

  • web/src/components/ui/dept-health-bar.stories.tsx
  • CLAUDE.md
  • web/src/__tests__/components/ui/dept-health-bar.test.tsx
  • web/src/pages/dashboard/OrgHealthSection.stories.tsx
  • web/src/pages/org/DepartmentStatsBar.stories.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:

  • CLAUDE.md
  • docs/design/brand-and-ux.md
📚 Learning: 2026-03-29T11:41:44.483Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-29T11:41:44.483Z
Learning: Applies to web/src/pages/**/*.{ts,tsx} : Web dashboard pages: Lazy-loaded page components (one per route). Page-scoped sub-components in `pages/<page-name>/` subdirs. Feature dirs added as pages are built. Stores for auth, WebSocket, toast, analytics, setup wizard, company, agents, budget, tasks, settings, providers, theme.

Applied to files:

  • CLAUDE.md
  • web/src/pages/dashboard/DashboardPage.stories.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-edit/DepartmentsTab.test.tsx
  • web/src/__tests__/components/ui/dept-health-bar.test.tsx
  • web/src/__tests__/utils/dashboard.test.ts
  • web/src/__tests__/pages/dashboard/OrgHealthSection.test.tsx
  • web/src/__tests__/utils/dashboard.property.test.ts
  • web/src/__tests__/pages/org/build-org-tree.test.ts
  • web/src/__tests__/pages/org/DepartmentStatsBar.test.tsx
📚 Learning: 2026-03-29T11:41:44.483Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-29T11:41:44.483Z
Learning: Applies to src/synthorg/hr/**/*.py : HR: Hiring, firing, onboarding, agent registry, performance tracking, activity timeline, career history, promotion/demotion.

Applied to files:

  • web/src/api/types.ts
📚 Learning: 2026-03-29T11:41:44.483Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-29T11:41:44.483Z
Learning: Applies to web/src/**/*.{ts,tsx,css} : Design tokens: Colors use Tailwind semantic classes (`text-foreground`, `bg-card`, `text-accent`, etc.) or CSS variables (`var(--so-accent)`). NEVER hardcode hex values. Typography uses `font-sans` or `font-mono`. Spacing uses density-aware tokens or standard Tailwind. Shadows/borders use token variables.

Applied to files:

  • docs/design/brand-and-ux.md
📚 Learning: 2026-03-29T11:41:44.483Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-29T11:41:44.483Z
Learning: Applies to **/*.{ts,tsx,json} : TypeScript 6.0: Remove `baseUrl` (deprecated); `paths` entries are relative to tsconfig directory. `esModuleInterop` always true—cannot be set to `false`. `types` defaults to `[]`—must explicitly list (e.g. `'types': ['vitest/globals']`). `DOM.Iterable` merged into `DOM`. `moduleResolution: 'classic'` and `'node10'` removed—use `'bundler'` or `'nodenext'`. `strict` defaults to `true`. `noUncheckedSideEffectImports` defaults to `true`.

Applied to files:

  • web/src/__tests__/helpers/factories.ts

| `SectionCard` | `section-card.tsx` | `title`, `icon?`, `action?`, `children` | Titled card wrapper with Lucide icon, action slot, and content area. Use for every content section. |
| `AgentCard` | `agent-card.tsx` | `name`, `role`, `department`, `status`, `currentTask?`, `timestamp?` | Consistent agent display. Composes Avatar + StatusBadge internally. Must look identical everywhere. |
| `DeptHealthBar` | `dept-health-bar.tsx` | `name`, `health?`, `agentCount`, `taskCount?` | Animated horizontal fill bar with health percentage (null-safe -- shows N/A when health unavailable). Color auto-mapped via `getHealthColor()`. |
| `DeptHealthBar` | `dept-health-bar.tsx` | `name`, `health?`, `agentCount` | Animated horizontal fill bar with utilization percentage (null-safe -- shows N/A when health unavailable). Color auto-mapped via `getHealthColor()`. |
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

Fix stale terminology in DeptHealthBar docs.

Line [203] mixes “utilization percentage” with “health unavailable.” Use “utilization unavailable” for consistency with current API semantics.

✏️ Proposed wording tweak
-| `DeptHealthBar` | `dept-health-bar.tsx` | `name`, `health?`, `agentCount` | Animated horizontal fill bar with utilization percentage (null-safe -- shows N/A when health unavailable). Color auto-mapped via `getHealthColor()`. |
+| `DeptHealthBar` | `dept-health-bar.tsx` | `name`, `health?`, `agentCount` | Animated horizontal fill bar with utilization percentage (null-safe -- shows N/A when utilization is unavailable). Color auto-mapped via `getHealthColor()`. |
📝 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
| `DeptHealthBar` | `dept-health-bar.tsx` | `name`, `health?`, `agentCount` | Animated horizontal fill bar with utilization percentage (null-safe -- shows N/A when health unavailable). Color auto-mapped via `getHealthColor()`. |
| `DeptHealthBar` | `dept-health-bar.tsx` | `name`, `health?`, `agentCount` | Animated horizontal fill bar with utilization percentage (null-safe -- shows N/A when utilization is unavailable). Color auto-mapped via `getHealthColor()`. |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/design/brand-and-ux.md` at line 203, Update the docs for DeptHealthBar
in dept-health-bar.tsx: replace the phrase "utilization percentage (null-safe --
shows N/A when health unavailable)" with wording that uses "utilization
unavailable" to match the API semantics (for example: "utilization (null-safe —
shows N/A when utilization unavailable)"). Keep the rest of the description
(animated horizontal fill, color auto-mapped via getHealthColor()) unchanged.

Update DeptHealthBar docs to say "utilization unavailable" instead of
"health unavailable". Add a11y test parameter to AgentGridView stories.
Fix build-org-tree test makeAgent signature to accept optional id
instead of using unsafe undefined cast.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@Aureliolo Aureliolo temporarily deployed to cloudflare-preview March 29, 2026 21:24 — with GitHub Actions Inactive
@Aureliolo Aureliolo merged commit 134c11b into main Mar 30, 2026
32 checks passed
@Aureliolo Aureliolo deleted the fix/type-alignment-websocket branch March 30, 2026 06:16
@Aureliolo Aureliolo temporarily deployed to cloudflare-preview March 30, 2026 06:16 — with GitHub Actions Inactive
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

1 participant