Skip to content

feat: Agent Profiles and Detail pages (biography, career, performance)#874

Merged
Aureliolo merged 9 commits intomainfrom
feat/agent-profiles-page
Mar 27, 2026
Merged

feat: Agent Profiles and Detail pages (biography, career, performance)#874
Aureliolo merged 9 commits intomainfrom
feat/agent-profiles-page

Conversation

@Aureliolo
Copy link
Copy Markdown
Owner

Summary

  • Agent Profiles list page (/agents): responsive grid of AgentCards with filtering (department, level, status), search by name/role, sorting (name, department, level, status, hire date), polling + WebSocket real-time updates
  • Agent Detail page (/agents/:agentName): biography-style profile with identity header, prose insights, 2x2 performance MetricCards with sparklines, tool badges, vertical career timeline, Gantt-style task history bars, paginated activity log
  • Data layer: 7 new TypeScript types mirroring backend models, 3 new API endpoint functions, full Zustand store with Promise.allSettled graceful degradation, 2 composite data hooks (list + detail)
  • Pure utilities: filtering, sorting, status mapping, performance card computation, prose insight generation, formatting, career event colors, activity event icons
  • Tests: 690 total (78 new) -- unit tests, fast-check property tests, store action tests
  • Storybook: 10 new story files covering all page-scoped components with multiple variants
  • Docs updated: docs/design/page-structure.md updated to reflect full-page layout (vs original slide-in spec), CLAUDE.md package structure descriptions updated

Test plan

  • npm --prefix web run type-check -- clean
  • npm --prefix web run lint -- 0 errors (1 pre-existing warning in inline-edit.tsx)
  • npm --prefix web run test -- 690/690 pass
  • Pre-commit hooks pass (ruff, gitleaks, commitizen, no-em-dashes)
  • Pre-push hooks pass
  • Verify in Storybook: all 10 new story files render correctly
  • Verify list page filtering/search/sort with live backend
  • Verify detail page sections populate from API data

Review coverage

Pre-reviewed by 6 agents (frontend-reviewer, api-contract-drift, type-design-analyzer, test-quality-reviewer, issue-resolution-verifier, docs-consistency). 17 findings addressed in a follow-up commit.

Closes #779

🤖 Generated with Claude Code

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 27, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 6072dc2c-7b08-4b02-899c-eda0994e1e7c

📥 Commits

Reviewing files that changed from the base of the PR and between b5bd49f and 6405d1f.

📒 Files selected for processing (1)
  • web/src/__tests__/stores/agents.test.ts
📜 Recent review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: Dashboard Test
  • GitHub Check: Build Backend
  • GitHub Check: Build Sandbox
  • GitHub Check: Dependency Review
  • GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (1)
web/src/**/*.{tsx,ts}

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • web/src/__tests__/stores/agents.test.ts
🧠 Learnings (3)
📓 Common learnings
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:20:09.993Z
Learning: Applies to web/src/components/** : Vue components organized by feature (agents/, approvals/, budget/, common/, dashboard/, layout/, messages/, org-chart/, tasks/).
📚 Learning: 2026-03-20T08:28:32.845Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-20T08:28:32.845Z
Learning: Applies to web/src/__tests__/**/*.{ts,js} : Dashboard testing: Vitest unit tests organized by feature under `web/src/__tests__/`. Use fast-check for property-based testing (`fc.assert` + `fc.property`).

Applied to files:

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

Applied to files:

  • web/src/__tests__/stores/agents.test.ts
🔇 Additional comments (4)
web/src/__tests__/stores/agents.test.ts (4)

77-104: Typed makeTask fixture is a solid improvement.

Nice upgrade from unsafe casting to a strongly typed factory; this makes state seeding safer and future type changes easier to catch.


239-270: Excellent stale-response race coverage.

This test cleanly validates that overlapping fetchAgentDetail() calls keep the latest result and reject stale resolution order.


272-292: Great in-flight invalidation test after clearDetail().

Good guardrail for navigation-away behavior; it verifies late responses cannot repopulate cleared detail state.


386-412: clearDetail reset assertions are now complete.

Seeding non-empty arrays and asserting each detail slice is cleared provides strong regression protection for reset behavior.


Walkthrough

Adds a complete Agents feature: list and detail pages with router-driven detail route, filtering/search/sort, skeletons, and grid/list views. Introduces UI components (identity header, prose insights, performance metrics, tool badges, career timeline, task history, paginated activity log) and Storybook stories. Adds API client endpoints and types for performance, activity, and career history. Replaces the empty Zustand agents store with a full AgentsState and actions. Adds utilities for filtering/sorting/formatting, two hooks (useAgentsData, useAgentDetailData) with polling and WebSocket bindings, and comprehensive unit and property tests.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 23.40% which is insufficient. The required threshold is 40.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: adding Agent Profiles and Detail pages with biography, career, and performance sections.
Description check ✅ Passed The description is comprehensive and relates directly to the changeset, covering all key features, implementation layers, tests, and documentation updates.
Linked Issues check ✅ Passed All primary objectives from issue #779 are met: agent list/detail pages with filtering/search/sort, identity/performance/tools/career/task/activity sections, data endpoints, tests, and Storybook stories.
Out of Scope Changes check ✅ Passed All changes are in scope for issue #779. CLAUDE.md documentation updates and page-structure.md reflect the new design; no unrelated functionality introduced.

✏️ 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 27, 2026 11:33 — with GitHub Actions Inactive
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 27, 2026

Dependency Review

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

Snapshot Warnings

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

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

Choose a reason for hiding this comment

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

Code Review

This pull request implements the Agent Detail page and associated functionality, including new API endpoints for performance, activity, and career history, along with the necessary Zustand store actions and React hooks. The review feedback highlights opportunities to improve test readability by refactoring mock setups, enhancing hook dependency management to avoid eslint-disable comments, strengthening type safety for filter inputs, ensuring unique keys for list items, and improving the user experience during data refreshes by preserving stale data when secondary fetches fail.

Comment on lines +195 to +207
it('sets error when agent fetch fails', async () => {
vi.mocked(getAgent).mockRejectedValue(new Error('Not found'))
vi.mocked(getAgentPerformance).mockRejectedValue(new Error('fail'))
vi.mocked(listTasks).mockRejectedValue(new Error('fail'))
vi.mocked(getAgentActivity).mockRejectedValue(new Error('fail'))
vi.mocked(getAgentHistory).mockRejectedValue(new Error('fail'))

await useAgentsStore.getState().fetchAgentDetail('Unknown')

const state = useAgentsStore.getState()
expect(state.selectedAgent).toBeNull()
expect(state.detailError).toBeTruthy()
})
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The tests for fetchAgentDetail have some repeated mock setups for failure cases. While this works, you could reduce duplication and improve readability by creating a helper function to set up the default mock resolved values, and then override specific mocks to reject in each test case. This would make the intent of each test (i.e., which specific API call is failing) clearer.

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

Choose a reason for hiding this comment

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

medium

The eslint-disable-next-line @eslint-react/exhaustive-deps comment suggests a potential issue with hook dependencies. While the current logic with [agentName] works because polling is recreated when agentName changes, it's more idiomatic and robust to depend directly on the polling object. This makes the dependency explicit and allows removing the eslint-disable comment.

  useEffect(() => {
    polling.start()
    return () => polling.stop()
  }, [polling])

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

Choose a reason for hiding this comment

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

medium

The eslint-disable-next-line @eslint-react/exhaustive-deps comment can be addressed by making the useEffect hook depend directly on the polling object. This is a more robust pattern for handling hook dependencies and makes the code clearer. Since pollFn is stable in this hook, polling will also be stable, and the effect will correctly run only once on mount.

  useEffect(() => {
    polling.start()
    return () => polling.stop()
  }, [polling])

{/* Department */}
<select
value={departmentFilter ?? ''}
onChange={(e) => setDepartmentFilter(e.target.value ? e.target.value as typeof departmentFilter : null)}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The type cast as typeof departmentFilter is not type-safe because it doesn't validate that e.target.value is a valid DepartmentName. This could allow invalid data into your application state. A safer approach is to use a type guard or an inline check to validate the value before casting. This concern also applies to the level and status filters.

) : (
<StaggerGroup className="divide-y divide-border">
{events.map((event) => (
<StaggerItem key={`${event.event_type}-${event.timestamp}-${event.description.slice(0, 20)}`}>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The key for this list item is constructed from multiple properties, including a sliced description. This could lead to non-unique keys if two events have the same type, timestamp, and similar descriptions. If the backend could provide a unique ID for each activity event, that would be a more robust solution for the key prop.

Comment on lines +99 to +106
const [agentResult, perfResult, tasksResult, activityResult, historyResult] =
await Promise.allSettled([
getAgent(name),
getAgentPerformance(name),
listTasks({ assigned_to: name, limit: 50 }),
getAgentActivity(name, { limit: 20 }),
getAgentHistory(name),
])
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

Using Promise.allSettled is a great choice for gracefully handling failures of non-critical data fetches on the detail page. However, the subsequent set call overwrites existing data (e.g., agentTasks) with an empty array if its corresponding promise was rejected. For a better user experience during data refreshes (e.g., via polling), consider preserving the stale data if a fetch fails, and perhaps show a small, non-blocking error indicator for the failed section.

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

🤖 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/page-structure.md`:
- Around line 67-82: Update the spec so the Agent Detail is consistently modeled
as a full-page route `/agents/{agentName}` everywhere: replace any references to
a slide-in "Agent Detail panel" with "Agent Detail page" in the URL Routing Map,
Overlays section, WebSocket subscription table, and Controller-to-Page Map;
ensure the WebSocket channels list includes the `agents` and `tasks`
subscriptions scoped for the detail page, update controller mappings to point
controllers/actions (e.g., AgentController -> AgentDetailPage) to the new
full-page route, and remove or mark deprecated any tab/controller mappings that
assumed an overlay-based flow so the doc consistently reflects the single-page
navigation model described by the Agent Detail page and its sections (Identity
header, Prose insights, Performance metrics, Tool badges, Career timeline, Task
history, Activity log).

In `@web/src/__tests__/utils/agents.property.test.ts`:
- Around line 81-115: arbWindowMetrics and arbPerformance produce impossible
payloads because counters are generated independently; fix by generating
dependent values deterministically: for arbWindowMetrics, first generate
data_point_count then derive tasks_completed and tasks_failed (e.g., sample
tasks_completed in [0,data_point_count] and set tasks_failed = data_point_count
- tasks_completed) and keep other optional floats as-is; for arbPerformance,
ensure tasks_completed_7d and tasks_completed_30d are ≤ tasks_completed_total
(generate tasks_completed_total first and then sample the 7d/30d values from it)
and keep windows/trends arrays consistent by constructing them with fc.array of
arbWindowMetrics/arbTrendResult where needed; update arbWindowMetrics,
arbPerformance (and any mapping code) to use fc.tuple/fc.record(...).map(...) to
enforce these invariants.

In `@web/src/__tests__/utils/agents.test.ts`:
- Around line 311-313: The test for formatCostPerTask currently expects
'$-5.00', which may be a surprising UX; please decide the intended negative
format (e.g., '-$5.00' or '($5.00)') or whether negatives are invalid, then
either (a) update the implementation of formatCostPerTask to format negatives in
the chosen convention and change this test expectation to match, or (b) if
'$-5.00' is intentional, add a clarifying comment in the test to explain the
decision; reference formatCostPerTask and the test case that asserts
formatCostPerTask(-5).

In `@web/src/hooks/useAgentDetailData.ts`:
- Around line 90-93: fetchMoreActivity is being recreated whenever
activity.length changes because it's included in the dependency array; to avoid
unnecessary re-renders when passing this callback to children, replace the
direct dependency on activity.length with a mutable ref: create an offsetRef
that you update in a useEffect when activity.length changes, then have
fetchMoreActivity read offsetRef.current and depend only on agentName (or be
stable via useCallback with an empty deps array if agentName is constant).
Update references to useAgentsStore.getState().fetchMoreActivity(agentName,
offsetRef.current) inside fetchMoreActivity and remove activity.length from the
dependency list.
- Around line 45-51: The fetchAgentDetail flow can overwrite newer agent data
when navigation is fast; update the store's fetchAgentDetail implementation in
useAgentsStore to guard against stale responses by recording the requested
agentName (or a requestId) before awaiting Promise.allSettled and, after each
awaited result, verify the resolved agent name/requestId matches the latest
requested value before calling set() to update selectedAgent (alternatively
implement AbortController to cancel prior requests); no changes needed in the
hook (useAgentDetailData) other than the existing clearDetail call.

In `@web/src/pages/AgentDetailPage.tsx`:
- Line 65: Wrap the ProseInsight component in an ErrorBoundary with
level="section" to match other sections (AgentIdentityHeader,
PerformanceMetrics, ToolBadges, CareerTimeline, TaskHistory, ActivityLog);
specifically, replace the lone <ProseInsight insights={insights} /> with an
<ErrorBoundary level="section"> that renders <ProseInsight insights={insights}
/> as its child so any rendering errors from ProseInsight are contained and
consistent with the rest of the page.

In `@web/src/pages/agents/ActivityLog.tsx`:
- Around line 40-44: The composite React key used in the events.map render
(inside StaggerItem / ActivityLogItem) can collide because AgentActivityEvent
has no id; replace the fragile template key with a stable unique value such as
the array index or the full description combined with index to guarantee
uniqueness (e.g., use the map index or description+index) so keys are
deterministic and avoid collisions when rendering the events list.

In `@web/src/pages/agents/ActivityLogItem.tsx`:
- Around line 18-20: Replace the non-semantic span used for the timestamp with a
semantic time element: in ActivityLogItem.tsx update the element rendering
formatRelativeTime(event.timestamp) to use <time dateTime={event.timestamp}>
(preserve the existing className "text-micro font-mono text-muted-foreground
shrink-0" and the displayed value from formatRelativeTime). Ensure dateTime
receives the same event.timestamp value (ISO/UTC string) so browsers and
assistive tech can parse it.

In `@web/src/pages/agents/AgentFilters.stories.tsx`:
- Around line 6-27: The Storybook meta for the AgentFilters story is missing the
accessibility test configuration; update the exported meta object (meta) to
include a parameters field with an a11y subfield and set test to one of the
allowed values ('error' | 'todo' | 'off') so Storybook will
run/accessibility-check this story (i.e., add parameters: { a11y: { test:
'error' } } or chosen level) alongside the existing title/component/decorators
entries.

In `@web/src/pages/agents/AgentIdentityHeader.stories.tsx`:
- Around line 30-37: Add an accessibility test configuration to the Storybook
story meta for AgentIdentityHeader by adding a parameters.a11y.test value
(choose 'error' or 'todo' per guideline) so the story's meta object includes the
a11y test setting; update the existing meta constant (the object named meta that
references AgentIdentityHeader and decorators) to include parameters: { a11y: {
test: '<error|todo|off>' } }.

In `@web/src/pages/agents/CareerTimeline.tsx`:
- Line 25: The StaggerItem key uses `${event.event_type}-${event.timestamp}`
which can collide; update the key in the CareerTimeline rendering (the
StaggerItem element) to use a guaranteed unique identifier such as `event.id` if
available, and fall back to appending the loop index (`i`) when `event.id` is
missing (e.g., `key={event.id ??
`${event.event_type}-${event.timestamp}-${i}`}`) so each StaggerItem has a
stable, unique key.

In `@web/src/pages/agents/CareerTimelineEvent.tsx`:
- Line 18: In CareerTimelineEvent replace the hardcoded left-[7px] on the
vertical line div (the element with classes "absolute left-[7px] top-4 bottom-0
w-px bg-border") with the appropriate design-token spacing utility used across
the codebase (e.g., the matching Tailwind/design-token class such as
left-<token>) so the component uses token-based spacing rather than a raw pixel
value; update the class string for that div to the correct token class and run
the app to verify the visual alignment remains correct.

In `@web/src/pages/agents/TaskHistory.tsx`:
- Around line 20-25: The reduce callback computing maxDurationMs contains an
unnecessary null guard for task.created_at because sorted was already filtered
to only tasks with created_at; remove the `if (!task.created_at) return max`
check and simplify the reducer in maxDurationMs to assume task.created_at
exists, still computing end = task.updated_at ?? task.created_at and duration
accordingly using the sorted.reduce function.

In `@web/src/pages/agents/ToolBadges.tsx`:
- Around line 17-28: The JSX inside the tools.map in ToolBadges.tsx is too
large—extract the badge rendering into a small shared component (e.g., ToolBadge
accepting a tool prop and using formatLabel) and replace the inline block with
<ToolBadge tool={tool} /> in the map; also fix the fragile key={tool} by using a
stable unique key (e.g., combine tool with the map index or another unique
identifier such as `${tool}-${index}`) to avoid collisions when duplicate tool
names exist.

In `@web/src/pages/AgentsPage.tsx`:
- Around line 30-42: The error and connectivity banners in AgentsPage.tsx are
not announced by screen readers; update the two dynamic banner divs that render
when error and when !wsConnected && !loading (the blocks containing
AlertTriangle and WifiOff and the variables error and wsSetupError) to include
accessible live-region attributes (e.g., add role="alert" and
aria-live="assertive" or aria-live="polite" as appropriate) so screen readers
announce appearance/changes; ensure you apply this to both the error banner
(uses variable error and AlertTriangle) and the warning banner (uses
wsSetupError, wsConnected, loading and WifiOff).

In `@web/src/stores/agents.ts`:
- Around line 130-136: fetchMoreActivity is appending pages then slicing to
MAX_ACTIVITIES, which makes pagination stop while activityTotal still reports
the backend total; update fetchMoreActivity to short-circuit if
state.activity.length >= MAX_ACTIVITIES (do not call getAgentActivity), or after
receiving result clamp activityTotal to Math.min(result.total, MAX_ACTIVITIES)
and only merge result.data if the current selectedAgent still matches the agent
name; ensure you reference fetchMoreActivity, MAX_ACTIVITIES, activity,
activityTotal, selectedAgent and getAgentActivity so responses for stale agents
are ignored and the visible total never exceeds the client cap.

In `@web/src/utils/agents.ts`:
- Around line 162-165: The generateInsights function currently ignores the
_agent parameter; update it to use agent-specific fields (e.g., name, role,
department) to produce richer insight strings: remove the underscore prefix from
the parameter (or reference it directly as agent), read available properties
from AgentConfig inside generateInsights, incorporate them into the generated
messages (with sensible fallbacks when fields are missing), and ensure you still
handle perf === null as before so you don't break existing behavior.
🪄 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: 13e7e619-fbff-4b94-ad7e-05dcd8ba4d99

📥 Commits

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

📒 Files selected for processing (37)
  • CLAUDE.md
  • docs/design/page-structure.md
  • web/src/__tests__/stores/agents.test.ts
  • web/src/__tests__/utils/agents.property.test.ts
  • web/src/__tests__/utils/agents.test.ts
  • web/src/api/endpoints/agents.ts
  • web/src/api/types.ts
  • web/src/hooks/useAgentDetailData.ts
  • web/src/hooks/useAgentsData.ts
  • web/src/pages/AgentDetailPage.tsx
  • web/src/pages/AgentsPage.tsx
  • web/src/pages/agents/ActivityLog.stories.tsx
  • web/src/pages/agents/ActivityLog.tsx
  • web/src/pages/agents/ActivityLogItem.tsx
  • web/src/pages/agents/AgentDetailSkeleton.stories.tsx
  • web/src/pages/agents/AgentDetailSkeleton.tsx
  • web/src/pages/agents/AgentFilters.stories.tsx
  • web/src/pages/agents/AgentFilters.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/agents/AgentsSkeleton.tsx
  • web/src/pages/agents/CareerTimeline.stories.tsx
  • web/src/pages/agents/CareerTimeline.tsx
  • web/src/pages/agents/CareerTimelineEvent.tsx
  • web/src/pages/agents/PerformanceMetrics.stories.tsx
  • web/src/pages/agents/PerformanceMetrics.tsx
  • web/src/pages/agents/ProseInsight.stories.tsx
  • web/src/pages/agents/ProseInsight.tsx
  • web/src/pages/agents/TaskHistory.stories.tsx
  • web/src/pages/agents/TaskHistory.tsx
  • web/src/pages/agents/TaskHistoryBar.tsx
  • web/src/pages/agents/ToolBadges.stories.tsx
  • web/src/pages/agents/ToolBadges.tsx
  • web/src/stores/agents.ts
  • web/src/utils/agents.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: CI Pass
  • GitHub Check: Build Web
  • GitHub Check: Build Backend
  • GitHub Check: Build Sandbox
  • GitHub Check: Dependency Review
  • GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (9)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • web/src/pages/agents/ProseInsight.tsx
  • web/src/pages/agents/AgentDetailSkeleton.tsx
  • web/src/pages/agents/AgentsSkeleton.tsx
  • web/src/pages/agents/PerformanceMetrics.stories.tsx
  • web/src/pages/agents/CareerTimelineEvent.tsx
  • web/src/pages/agents/ToolBadges.tsx
  • web/src/pages/agents/CareerTimeline.tsx
  • web/src/pages/agents/AgentFilters.tsx
  • web/src/pages/agents/AgentIdentityHeader.tsx
  • web/src/__tests__/utils/agents.property.test.ts
  • web/src/pages/agents/AgentDetailSkeleton.stories.tsx
  • web/src/pages/agents/ActivityLogItem.tsx
  • web/src/pages/agents/ActivityLog.stories.tsx
  • web/src/api/endpoints/agents.ts
  • web/src/pages/agents/AgentGridView.tsx
  • web/src/pages/agents/AgentFilters.stories.tsx
  • web/src/pages/AgentDetailPage.tsx
  • web/src/pages/agents/ToolBadges.stories.tsx
  • web/src/pages/agents/PerformanceMetrics.tsx
  • web/src/pages/agents/ProseInsight.stories.tsx
  • web/src/__tests__/utils/agents.test.ts
  • web/src/pages/agents/ActivityLog.tsx
  • web/src/pages/agents/AgentGridView.stories.tsx
  • web/src/pages/agents/CareerTimeline.stories.tsx
  • web/src/hooks/useAgentsData.ts
  • web/src/api/types.ts
  • web/src/pages/agents/TaskHistory.stories.tsx
  • web/src/pages/agents/AgentIdentityHeader.stories.tsx
  • web/src/pages/AgentsPage.tsx
  • web/src/stores/agents.ts
  • web/src/__tests__/stores/agents.test.ts
  • web/src/hooks/useAgentDetailData.ts
  • web/src/pages/agents/TaskHistoryBar.tsx
  • web/src/pages/agents/TaskHistory.tsx
  • web/src/utils/agents.ts
web/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • web/src/pages/agents/ProseInsight.tsx
  • web/src/pages/agents/AgentDetailSkeleton.tsx
  • web/src/pages/agents/AgentsSkeleton.tsx
  • web/src/pages/agents/PerformanceMetrics.stories.tsx
  • web/src/pages/agents/CareerTimelineEvent.tsx
  • web/src/pages/agents/ToolBadges.tsx
  • web/src/pages/agents/CareerTimeline.tsx
  • web/src/pages/agents/AgentFilters.tsx
  • web/src/pages/agents/AgentIdentityHeader.tsx
  • web/src/__tests__/utils/agents.property.test.ts
  • web/src/pages/agents/AgentDetailSkeleton.stories.tsx
  • web/src/pages/agents/ActivityLogItem.tsx
  • web/src/pages/agents/ActivityLog.stories.tsx
  • web/src/api/endpoints/agents.ts
  • web/src/pages/agents/AgentGridView.tsx
  • web/src/pages/agents/AgentFilters.stories.tsx
  • web/src/pages/AgentDetailPage.tsx
  • web/src/pages/agents/ToolBadges.stories.tsx
  • web/src/pages/agents/PerformanceMetrics.tsx
  • web/src/pages/agents/ProseInsight.stories.tsx
  • web/src/__tests__/utils/agents.test.ts
  • web/src/pages/agents/ActivityLog.tsx
  • web/src/pages/agents/AgentGridView.stories.tsx
  • web/src/pages/agents/CareerTimeline.stories.tsx
  • web/src/hooks/useAgentsData.ts
  • web/src/api/types.ts
  • web/src/pages/agents/TaskHistory.stories.tsx
  • web/src/pages/agents/AgentIdentityHeader.stories.tsx
  • web/src/pages/AgentsPage.tsx
  • web/src/stores/agents.ts
  • web/src/__tests__/stores/agents.test.ts
  • web/src/hooks/useAgentDetailData.ts
  • web/src/pages/agents/TaskHistoryBar.tsx
  • web/src/pages/agents/TaskHistory.tsx
  • web/src/utils/agents.ts
web/src/pages/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • web/src/pages/agents/ProseInsight.tsx
  • web/src/pages/agents/AgentDetailSkeleton.tsx
  • web/src/pages/agents/AgentsSkeleton.tsx
  • web/src/pages/agents/PerformanceMetrics.stories.tsx
  • web/src/pages/agents/CareerTimelineEvent.tsx
  • web/src/pages/agents/ToolBadges.tsx
  • web/src/pages/agents/CareerTimeline.tsx
  • web/src/pages/agents/AgentFilters.tsx
  • web/src/pages/agents/AgentIdentityHeader.tsx
  • web/src/pages/agents/AgentDetailSkeleton.stories.tsx
  • web/src/pages/agents/ActivityLogItem.tsx
  • web/src/pages/agents/ActivityLog.stories.tsx
  • web/src/pages/agents/AgentGridView.tsx
  • web/src/pages/agents/AgentFilters.stories.tsx
  • web/src/pages/AgentDetailPage.tsx
  • web/src/pages/agents/ToolBadges.stories.tsx
  • web/src/pages/agents/PerformanceMetrics.tsx
  • web/src/pages/agents/ProseInsight.stories.tsx
  • web/src/pages/agents/ActivityLog.tsx
  • web/src/pages/agents/AgentGridView.stories.tsx
  • web/src/pages/agents/CareerTimeline.stories.tsx
  • web/src/pages/agents/TaskHistory.stories.tsx
  • web/src/pages/agents/AgentIdentityHeader.stories.tsx
  • web/src/pages/AgentsPage.tsx
  • web/src/pages/agents/TaskHistoryBar.tsx
  • web/src/pages/agents/TaskHistory.tsx
web/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • web/src/pages/agents/ProseInsight.tsx
  • web/src/pages/agents/AgentDetailSkeleton.tsx
  • web/src/pages/agents/AgentsSkeleton.tsx
  • web/src/pages/agents/PerformanceMetrics.stories.tsx
  • web/src/pages/agents/CareerTimelineEvent.tsx
  • web/src/pages/agents/ToolBadges.tsx
  • web/src/pages/agents/CareerTimeline.tsx
  • web/src/pages/agents/AgentFilters.tsx
  • web/src/pages/agents/AgentIdentityHeader.tsx
  • web/src/__tests__/utils/agents.property.test.ts
  • web/src/pages/agents/AgentDetailSkeleton.stories.tsx
  • web/src/pages/agents/ActivityLogItem.tsx
  • web/src/pages/agents/ActivityLog.stories.tsx
  • web/src/api/endpoints/agents.ts
  • web/src/pages/agents/AgentGridView.tsx
  • web/src/pages/agents/AgentFilters.stories.tsx
  • web/src/pages/AgentDetailPage.tsx
  • web/src/pages/agents/ToolBadges.stories.tsx
  • web/src/pages/agents/PerformanceMetrics.tsx
  • web/src/pages/agents/ProseInsight.stories.tsx
  • web/src/__tests__/utils/agents.test.ts
  • web/src/pages/agents/ActivityLog.tsx
  • web/src/pages/agents/AgentGridView.stories.tsx
  • web/src/pages/agents/CareerTimeline.stories.tsx
  • web/src/hooks/useAgentsData.ts
  • web/src/api/types.ts
  • web/src/pages/agents/TaskHistory.stories.tsx
  • web/src/pages/agents/AgentIdentityHeader.stories.tsx
  • web/src/pages/AgentsPage.tsx
  • web/src/stores/agents.ts
  • web/src/__tests__/stores/agents.test.ts
  • web/src/hooks/useAgentDetailData.ts
  • web/src/pages/agents/TaskHistoryBar.tsx
  • web/src/pages/agents/TaskHistory.tsx
  • web/src/utils/agents.ts
web/**

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • web/src/pages/agents/ProseInsight.tsx
  • web/src/pages/agents/AgentDetailSkeleton.tsx
  • web/src/pages/agents/AgentsSkeleton.tsx
  • web/src/pages/agents/PerformanceMetrics.stories.tsx
  • web/src/pages/agents/CareerTimelineEvent.tsx
  • web/src/pages/agents/ToolBadges.tsx
  • web/src/pages/agents/CareerTimeline.tsx
  • web/src/pages/agents/AgentFilters.tsx
  • web/src/pages/agents/AgentIdentityHeader.tsx
  • web/src/__tests__/utils/agents.property.test.ts
  • web/src/pages/agents/AgentDetailSkeleton.stories.tsx
  • web/src/pages/agents/ActivityLogItem.tsx
  • web/src/pages/agents/ActivityLog.stories.tsx
  • web/src/api/endpoints/agents.ts
  • web/src/pages/agents/AgentGridView.tsx
  • web/src/pages/agents/AgentFilters.stories.tsx
  • web/src/pages/AgentDetailPage.tsx
  • web/src/pages/agents/ToolBadges.stories.tsx
  • web/src/pages/agents/PerformanceMetrics.tsx
  • web/src/pages/agents/ProseInsight.stories.tsx
  • web/src/__tests__/utils/agents.test.ts
  • web/src/pages/agents/ActivityLog.tsx
  • web/src/pages/agents/AgentGridView.stories.tsx
  • web/src/pages/agents/CareerTimeline.stories.tsx
  • web/src/hooks/useAgentsData.ts
  • web/src/api/types.ts
  • web/src/pages/agents/TaskHistory.stories.tsx
  • web/src/pages/agents/AgentIdentityHeader.stories.tsx
  • web/src/pages/AgentsPage.tsx
  • web/src/stores/agents.ts
  • web/src/__tests__/stores/agents.test.ts
  • web/src/hooks/useAgentDetailData.ts
  • web/src/pages/agents/TaskHistoryBar.tsx
  • web/src/pages/agents/TaskHistory.tsx
  • web/src/utils/agents.ts
web/**/*.stories.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • web/src/pages/agents/PerformanceMetrics.stories.tsx
  • web/src/pages/agents/AgentDetailSkeleton.stories.tsx
  • web/src/pages/agents/ActivityLog.stories.tsx
  • web/src/pages/agents/AgentFilters.stories.tsx
  • web/src/pages/agents/ToolBadges.stories.tsx
  • web/src/pages/agents/ProseInsight.stories.tsx
  • web/src/pages/agents/AgentGridView.stories.tsx
  • web/src/pages/agents/CareerTimeline.stories.tsx
  • web/src/pages/agents/TaskHistory.stories.tsx
  • web/src/pages/agents/AgentIdentityHeader.stories.tsx
web/src/__tests__/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • web/src/__tests__/utils/agents.property.test.ts
  • web/src/__tests__/utils/agents.test.ts
  • web/src/__tests__/stores/agents.test.ts
docs/**/*.md

📄 CodeRabbit inference engine (CLAUDE.md)

Use Zensical for Markdown documentation build with mkdocs.yml config; docs in docs/ directory; design spec in docs/design/ (11 pages)

Files:

  • docs/design/page-structure.md
web/src/stores/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

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

Applied to files:

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

Applied to files:

  • CLAUDE.md
  • web/src/pages/agents/CareerTimelineEvent.tsx
  • web/src/pages/agents/ToolBadges.tsx
  • web/src/pages/agents/CareerTimeline.tsx
  • web/src/pages/agents/AgentFilters.tsx
  • web/src/pages/agents/ActivityLogItem.tsx
  • web/src/hooks/useAgentsData.ts
  • web/src/pages/agents/TaskHistoryBar.tsx
  • web/src/pages/agents/TaskHistory.tsx
  • web/src/utils/agents.ts
📚 Learning: 2026-03-27T09:44:40.059Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T09:44:40.059Z
Learning: Applies to web/src/components/ui/**/*.{ts,tsx} : When creating new shared React components, place them in `web/src/components/ui/` with kebab-case filename, create accompanying `.stories.tsx` Storybook file with all states, export TypeScript interface for props, and use design tokens exclusively

Applied to files:

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

Applied to files:

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

Applied to files:

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

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-15T18:17:43.675Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Applies to web/** : Web dashboard: Node.js 20+, dependencies in web/package.json (Vue 3, PrimeVue, Tailwind CSS, Pinia, VueFlow, ECharts, Axios, vue-draggable-plus, Vitest, fast-check, ESLint, vue-tsc).

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-15T21:20:09.993Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:20:09.993Z
Learning: Applies to web/src/components/** : Vue components organized by feature (agents/, approvals/, budget/, common/, dashboard/, layout/, messages/, org-chart/, tasks/).

Applied to files:

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

Applied to files:

  • CLAUDE.md
  • web/src/pages/AgentDetailPage.tsx
📚 Learning: 2026-03-14T15:43:05.601Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-14T15:43:05.601Z
Learning: Applies to web/package.json : Web dashboard Node.js 20+; dependencies in web/package.json (Vue 3, PrimeVue, Tailwind CSS, Pinia, VueFlow, ECharts, Axios, vue-draggable-plus, Vitest, ESLint, vue-tsc)

Applied to files:

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

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

Applied to files:

  • web/src/pages/agents/AgentDetailSkeleton.tsx
  • web/src/pages/agents/AgentsSkeleton.tsx
  • web/src/pages/agents/PerformanceMetrics.stories.tsx
  • web/src/pages/agents/CareerTimelineEvent.tsx
  • web/src/pages/agents/ToolBadges.tsx
  • web/src/pages/agents/CareerTimeline.tsx
  • web/src/pages/agents/AgentFilters.tsx
  • web/src/pages/agents/AgentIdentityHeader.tsx
  • web/src/pages/agents/ActivityLogItem.tsx
  • web/src/pages/agents/AgentGridView.tsx
  • web/src/pages/agents/AgentFilters.stories.tsx
  • web/src/pages/AgentDetailPage.tsx
  • web/src/pages/agents/ToolBadges.stories.tsx
  • web/src/pages/agents/PerformanceMetrics.tsx
  • web/src/__tests__/utils/agents.test.ts
  • web/src/pages/agents/ActivityLog.tsx
  • web/src/pages/agents/AgentGridView.stories.tsx
  • web/src/hooks/useAgentsData.ts
  • web/src/pages/AgentsPage.tsx
  • web/src/pages/agents/TaskHistoryBar.tsx
  • web/src/pages/agents/TaskHistory.tsx
  • web/src/utils/agents.ts
📚 Learning: 2026-03-27T09:44:40.059Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T09:44:40.059Z
Learning: Applies to web/src/**/*.{ts,tsx} : Do not build card-with-header layouts from scratch; use `<SectionCard>` component

Applied to files:

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

Applied to files:

  • web/src/pages/agents/PerformanceMetrics.stories.tsx
  • web/src/pages/agents/AgentDetailSkeleton.stories.tsx
  • web/src/pages/agents/ActivityLog.stories.tsx
  • web/src/pages/agents/AgentFilters.stories.tsx
  • web/src/pages/agents/ToolBadges.stories.tsx
  • web/src/pages/agents/ProseInsight.stories.tsx
  • web/src/pages/agents/AgentGridView.stories.tsx
  • web/src/pages/agents/CareerTimeline.stories.tsx
  • web/src/pages/agents/TaskHistory.stories.tsx
  • web/src/pages/agents/AgentIdentityHeader.stories.tsx
📚 Learning: 2026-03-27T09:44:40.059Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T09:44:40.059Z
Learning: Applies to web/src/**/*.{ts,tsx} : Do not create metric displays with `text-metric font-bold`; use `<MetricCard>` component

Applied to files:

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

Applied to files:

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

Applied to files:

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

Applied to files:

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

Applied to files:

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

Applied to files:

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

Applied to files:

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

Applied to files:

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

Applied to files:

  • web/src/pages/agents/AgentFilters.stories.tsx
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to docs/design/*.md : Design spec pages: 7 pages in `docs/design/` — index, agents, organization, communication, engine, memory, operations

Applied to files:

  • docs/design/page-structure.md
📚 Learning: 2026-03-16T06:24:56.341Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-16T06:24:56.341Z
Learning: Applies to docs/design/**/*.md : Design specification pages in `docs/design/` must be consulted before implementing features (7 pages: index, agents, organization, communication, engine, memory, operations)

Applied to files:

  • docs/design/page-structure.md
📚 Learning: 2026-03-19T07:13:44.964Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:13:44.964Z
Learning: Always read the relevant `docs/design/` page before implementing any feature or planning any issue — DESIGN_SPEC.md is a pointer file linking to 7 design pages (Agents, Organization, Communication, Engine, Memory, Operations)

Applied to files:

  • docs/design/page-structure.md
📚 Learning: 2026-03-14T15:43:05.601Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-14T15:43:05.601Z
Learning: Applies to docs/** : Docs source in docs/ (Markdown, built with Zensical); design spec in docs/design/ (7 pages: index, agents, organization, communication, engine, memory, operations)

Applied to files:

  • docs/design/page-structure.md
📚 Learning: 2026-03-15T18:38:44.202Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:38:44.202Z
Learning: Always read the relevant `docs/design/` page before implementing any feature or planning any issue. DESIGN_SPEC.md is a pointer file linking to the 7 design pages (index, agents, organization, communication, engine, memory, operations).

Applied to files:

  • docs/design/page-structure.md
📚 Learning: 2026-03-17T22:08:13.456Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T22:08:13.456Z
Learning: Engine: Agent orchestration, execution loops, parallel execution, task decomposition, routing, task assignment, centralized single-writer task state engine (TaskEngine), task lifecycle, recovery, shutdown, workspace isolation, coordination (multi-agent pipeline: TopologyDispatcher protocol, 4 dispatchers — SAS/centralized/decentralized/context-dependent, wave execution, workspace lifecycle integration, CoordinationSectionConfig company config bridge, build_coordinator factory), coordination error classification, prompt policy validation, checkpoint recovery (checkpoint/, per-turn persistence, heartbeat detection, CheckpointRecoveryStrategy), approval gate (escalation detection, context parking/resume, EscalationInfo/ResumePayload models), stagnation detection (stagnation/, StagnationDetector protocol, ToolRepetitionDetector, dual-signal analysis, corrective prompt injection), agent runtime state (AgentRuntimeState, lightweight per-agent execution status for dashboard queries and recove...

Applied to files:

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

Applied to files:

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

Applied to files:

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

127-131: Documentation update is clear and aligned with the new architecture.

The hook and store scope descriptions now match the page-composition direction introduced in this PR.

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

1-15: Skeleton composition is clean and consistent with the design system.

Good reuse of shared skeleton primitives and responsive layout behavior.

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

4-29: Story coverage is solid for key rendering states.

Single, multiple, and empty insight scenarios are all represented.

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

1-45: Detail skeleton mirrors page sections well.

This gives users a predictable loading structure and cleanly reuses shared skeleton components.

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

4-13: Story setup is appropriate for this skeleton component.

The decorator context and default state are enough for regression checks.

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

13-23: Good state coverage for the badge section.

Default, single-item, and empty-input stories are all present and useful.

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

21-23: The current implementation is correct. Insight strings are dynamically generated from performance metrics (success rate, trend, quality score) with interpolated numeric values, making duplicate strings extremely unlikely. Using the insight string as a key is appropriate for this data pattern.

			> Likely an incorrect or invalid review comment.
web/src/pages/AgentsPage.tsx (1)

17-19: Good initial-load guard with skeleton.

The Line 17 conditional avoids an empty-state flash during first fetch and cleanly hands off to the loaded layout.

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

13-37: Solid state coverage for this component.

Default, NullValues, and Empty map well to the component’s behavior branches and improve visual regression confidence.

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

21-87: Filter controls are cleanly wired to centralized state.

The controlled inputs/selects and store setters are consistent and straightforward, which should keep list filtering/sorting behavior predictable.

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

19-42: Nice composition with existing UI building blocks.

Using Avatar, StatusBadge, and StatPill here keeps the identity header consistent with the shared design system.

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

17-27: Good adherence to shared metrics/card primitives.

This correctly uses SectionCard + MetricCard composition and keeps empty-state handling explicit with the early return.

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

1-93: LGTM!

The page structure is well-organized with clear separation of concerns. Good use of:

  • Conditional rendering for loading/error states
  • Semantic design tokens for alert styling
  • ErrorBoundary wrappers for fault isolation
  • Defensive array spreading for readonly props
web/src/pages/agents/AgentGridView.tsx (1)

1-53: LGTM!

Well-implemented grid view with:

  • Proper URL encoding via encodeURIComponent(agent.name) for safe navigation
  • Reuse of existing UI components (AgentCard, EmptyState, StaggerGroup/StaggerItem)
  • Responsive grid breakpoints using design tokens (gap-grid-gap)
  • Good keyboard accessibility with focus-visible ring styles
web/src/pages/agents/TaskHistoryBar.tsx (1)

1-70: LGTM!

Clean implementation of the task duration bar with:

  • Proper edge case handling in getBarWidth and formatDuration for missing timestamps
  • Design token compliance for colors (bg-accent, bg-success, etc.) and fonts (font-sans, font-mono)
  • Conditional pulse animation for active tasks provides good visual feedback
  • Min/max clamping (20%-100%) ensures bars are always visible
web/src/pages/agents/TaskHistory.tsx (1)

1-46: LGTM!

Good use of existing UI components (SectionCard, EmptyState, StaggerGroup/StaggerItem) and clean data transformation logic. The descending sort by created_at and max duration calculation for relative bar widths are correctly implemented.

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

1-49: LGTM overall!

Good implementation with proper use of UI components and clean "Load more" pagination pattern via the SectionCard action slot.

web/src/api/endpoints/agents.ts (1)

36-60: LGTM!

The new API endpoints follow established patterns consistently:

  • Proper encodeURIComponent usage for path parameters
  • Correct response type handling (unwrap for single objects, unwrapPaginated for lists)
  • Clean async/await with proper TypeScript generics
web/src/pages/agents/AgentIdentityHeader.stories.tsx (1)

1-43: LGTM!

Good story coverage with the makeAgent helper pattern enabling clean overrides for different states. The five variants (Active, OnLeave, Terminated, NoAutonomy, CSuite) cover the key rendering paths.

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

1-54: LGTM!

Good story coverage with proper MemoryRouter context and Zustand store state management. The decorator pattern for resetting/configuring store state before each story is appropriate for testing filter UI states.

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

1-85: LGTM!

The hook is well-structured with clear separation of concerns:

  • Store selectors are granular (individual field subscriptions) for optimal re-render behavior
  • Polling lifecycle is correctly managed with start/stop cleanup
  • WebSocket bindings are correctly memoized with empty deps since AGENT_CHANNELS is a module-level constant
  • Client-side filtering/sorting is properly memoized with all relevant dependencies
web/src/hooks/useAgentDetailData.ts (1)

59-63: Verify polling restarts correctly on agentName change.

The polling effect depends on [agentName] but polling object reference changes on each render. The eslint-disable is intentional, but ensure usePolling internally handles re-creation gracefully when pollFn changes (since pollFn has [agentName] in its deps at line 56).

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

1-472: Good test coverage with thorough edge case handling.

The test suite covers:

  • All public utility functions with happy path and edge cases
  • Null/undefined handling
  • Case-insensitivity for search
  • Non-mutation verification for sorting
  • Boundary conditions (empty arrays, zero values)
web/src/__tests__/stores/agents.test.ts (3)

227-247: Good coverage of MAX_ACTIVITIES cap behavior.

The test correctly validates that combining 99 existing + 5 new events results in exactly 100 items after the slice. Since MAX_ACTIVITIES is not exported from the store, hardcoding 100 in the test is acceptable, though a code comment noting this coupling would help maintainability.


142-208: Excellent graceful degradation test coverage.

The tests thoroughly validate Promise.allSettled behavior:

  • Agent detail loads even when performance fails
  • Agent detail loads even when tasks and history fail
  • Error state only set when core agent fetch fails

This matches the PR objective of using Promise.allSettled for graceful degradation.


1-317: Comprehensive Zustand store test suite.

The test suite properly:

  • Mocks API endpoints with vi.mock and async imports
  • Resets store state in beforeEach
  • Tests async action success/failure paths
  • Validates loading state transitions
  • Covers all filter setter actions
  • Verifies clearDetail resets appropriate fields
web/src/utils/agents.ts (2)

1-228: Well-structured utility module with clear separation of concerns.

The module cleanly separates:

  • Type definitions for filters/sorting
  • Status mapping logic
  • Filter/sort transformations (non-mutating)
  • Formatting helpers with null handling
  • Performance card composition matching MetricCardProps
  • Prose insight generation with sensible limits
  • Icon/color mapping with exhaustive coverage

All functions are pure and testable.


93-99: The hiring_date field in AgentConfig is typed as string (required, non-optional), so null or undefined values are not possible according to TypeScript's type system. The sorting implementation is correct for string comparisons. No defensive null handling is needed.

			> Likely an incorrect or invalid review comment.

Comment on lines +311 to +313
it('formats negative cost with dollar sign', () => {
expect(formatCostPerTask(-5)).toBe('$-5.00')
})
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

Verify negative cost display is intentional.

The test asserts formatCostPerTask(-5) returns '$-5.00'. While technically correct per implementation, displaying negative costs with a leading dollar sign and minus (e.g., $-5.00) may be unexpected UX. Consider whether this should be '-$5.00' or '($5.00)' for accounting convention, or if negative costs are even valid in this domain.

🤖 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 311 - 313, The test for
formatCostPerTask currently expects '$-5.00', which may be a surprising UX;
please decide the intended negative format (e.g., '-$5.00' or '($5.00)') or
whether negatives are invalid, then either (a) update the implementation of
formatCostPerTask to format negatives in the chosen convention and change this
test expectation to match, or (b) if '$-5.00' is intentional, add a clarifying
comment in the test to explain the decision; reference formatCostPerTask and the
test case that asserts formatCostPerTask(-5).

Comment on lines +162 to +165
export function generateInsights(
_agent: AgentConfig,
perf: AgentPerformanceSummary | null,
): string[] {
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 using the _agent parameter for richer insights.

The _agent parameter is currently unused (prefixed with underscore). Future iterations could incorporate agent-specific context like department or role into insights (e.g., "As a senior engineer, Alice maintains a quality score of 8.2").

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

In `@web/src/utils/agents.ts` around lines 162 - 165, The generateInsights
function currently ignores the _agent parameter; update it to use agent-specific
fields (e.g., name, role, department) to produce richer insight strings: remove
the underscore prefix from the parameter (or reference it directly as agent),
read available properties from AgentConfig inside generateInsights, incorporate
them into the generated messages (with sensible fallbacks when fields are
missing), and ensure you still handle perf === null as before so you don't break
existing behavior.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 7

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@web/src/__tests__/utils/agents.property.test.ts`:
- Around line 267-274: The test incorrectly asserts a euro symbol for
formatCostPerTask even though the source value is
AgentPerformanceSummary.cost_per_task_usd; update the test to avoid baking a EUR
symbol: either assert only that the returned string is a non-empty
currency-formatted value (e.g., contains digits and a currency symbol via a
regex like /\d/ and /[^\d\s]/) or explicitly pass/convert the value to USD
before calling formatCostPerTask or set the formatter to USD; locate the
assertion in the test for formatCostPerTask and replace the hardcoded /€/ check
with a currency-agnostic assertion or an explicit USD-aware check so the test
matches the API contract.

In `@web/src/hooks/useAgentDetailData.ts`:
- Around line 92-95: The current fetchMoreActivity callback can fire overlapping
pagination requests using the same activity.length offset; prevent duplicate
pages by serializing calls: add a local in-hook guard (e.g. isFetchingMore ref
or state) inside the fetchMoreActivity defined in useAgentDetailData.ts so it
immediately returns if a fetch is in progress, call
useAgentsStore.getState().fetchMoreActivity(agentName, activity.length) only
when not busy, and clear the guard after the returned promise resolves/rejects
(or, if the store method is synchronous, change it to return a promise and await
it); reference the existing fetchMoreActivity callback and
useAgentsStore.getState().fetchMoreActivity to locate where to add the guard.
- Around line 46-79: The hook is currently calling
useAgentsStore.getState().fetchAgentDetail('') and starting polling/WebSocket
for an empty agentName; modify useAgentDetailData to early-return or skip setup
when agentName is falsy (e.g., if (!agentName) {
useAgentsStore.getState().clearDetail(); return { ...defaults... } } ), only run
the effect that calls fetchAgentDetail and the polling setup (pollFn/usePolling)
when agentName is truthy, and only build DETAIL_CHANNELS bindings / call
useWebSocket when agentName exists so fetchAgentDetail, polling.start/stop, and
WebSocket handlers are not invoked for an empty name; keep references to
useAgentsStore.getState().fetchAgentDetail, clearDetail, pollFn,
DETAIL_CHANNELS, usePolling and useWebSocket to locate where to add the guards.

In `@web/src/pages/agents/AgentFilters.tsx`:
- Line 18: VALID_SORT_KEYS in AgentFilters.tsx currently hard-codes only
['name','department','level','status','hiring_date'] and the corresponding
<select> options, which blocks the new sort modes; update the VALID_SORT_KEYS
Set to include 'performance', 'cost', and 'activity', and add matching option
entries to the component's sort <select> (the same select currently rendering
options around the block handling sort modes) so those keys are accepted and
selectable by the UI; keep the set and the select options in sync to avoid
rejected sorts.

In `@web/src/pages/agents/TaskHistory.tsx`:
- Around line 15-24: The maxDurationMs reduction uses task.updated_at without
validating it, causing NaN widths when updated_at is unparsable; update the
logic that builds sorted and maxDurationMs (references: sorted and maxDurationMs
in TaskHistory.tsx) to either filter out tasks with invalid updated_at
timestamps or coerce an invalid updated_at to the task.created_at value before
computing duration (i.e., ensure end = isValidDate(task.updated_at) ?
task.updated_at : task.created_at), so the reducer never produces NaN and
TaskHistoryBar.tsx stops rendering "NaN%" widths.

In `@web/src/stores/agents.ts`:
- Around line 147-168: fetchMoreActivity currently has no loading flag, so add
an activityLoading boolean to the store and use it inside fetchMoreActivity to
prevent duplicate requests and expose UI state: set activityLoading = true
before calling getAgentActivity(name, { offset, limit: 20 }) and clear it
(false) in both the success and catch branches (also short-circuit if
activityLoading is already true), keep using selectedAgent, activity, and
activityTotal as before and ensure getAgentActivity errors still preserve
existing activity while resetting activityLoading.

In `@web/src/utils/agents.ts`:
- Around line 136-139: The cost-per-task display is using the project default
currency formatter (EUR) via formatCostPerTask, causing USD values from
computePerformanceCards (cost_per_task_usd) to show the wrong symbol; update
formatCostPerTask to accept or derive the currency unit (e.g., add a currency
parameter or call with 'USD') and ensure callers like computePerformanceCards
pass the correct unit so formatCurrency is invoked with the USD currency option;
update the other usages around lines ~172-174 similarly to preserve the USD unit
in the UI.
🪄 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: 9f769171-6785-4ea4-a065-6d35b43abf94

📥 Commits

Reviewing files that changed from the base of the PR and between 5d47982 and 0809c4e.

📒 Files selected for processing (18)
  • docs/design/page-structure.md
  • web/src/__tests__/stores/agents.test.ts
  • web/src/__tests__/utils/agents.property.test.ts
  • web/src/__tests__/utils/agents.test.ts
  • web/src/api/types.ts
  • web/src/hooks/useAgentDetailData.ts
  • web/src/hooks/useAgentsData.ts
  • web/src/pages/AgentDetailPage.tsx
  • web/src/pages/AgentsPage.tsx
  • web/src/pages/agents/ActivityLog.tsx
  • web/src/pages/agents/ActivityLogItem.tsx
  • web/src/pages/agents/AgentFilters.tsx
  • web/src/pages/agents/CareerTimeline.tsx
  • web/src/pages/agents/CareerTimelineEvent.tsx
  • web/src/pages/agents/TaskHistory.tsx
  • web/src/pages/agents/ToolBadges.tsx
  • web/src/stores/agents.ts
  • web/src/utils/agents.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: Dashboard Test
  • GitHub Check: Build Web
  • GitHub Check: Build Sandbox
  • GitHub Check: Build Backend
  • GitHub Check: Dependency Review
  • GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (8)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • web/src/pages/AgentsPage.tsx
  • web/src/pages/agents/CareerTimelineEvent.tsx
  • web/src/pages/agents/ActivityLogItem.tsx
  • web/src/pages/agents/ToolBadges.tsx
  • web/src/pages/AgentDetailPage.tsx
  • web/src/pages/agents/CareerTimeline.tsx
  • web/src/pages/agents/TaskHistory.tsx
  • web/src/__tests__/utils/agents.property.test.ts
  • web/src/pages/agents/ActivityLog.tsx
  • web/src/pages/agents/AgentFilters.tsx
  • web/src/stores/agents.ts
  • web/src/hooks/useAgentsData.ts
  • web/src/hooks/useAgentDetailData.ts
  • web/src/api/types.ts
  • web/src/__tests__/stores/agents.test.ts
  • web/src/__tests__/utils/agents.test.ts
  • web/src/utils/agents.ts
web/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • web/src/pages/AgentsPage.tsx
  • web/src/pages/agents/CareerTimelineEvent.tsx
  • web/src/pages/agents/ActivityLogItem.tsx
  • web/src/pages/agents/ToolBadges.tsx
  • web/src/pages/AgentDetailPage.tsx
  • web/src/pages/agents/CareerTimeline.tsx
  • web/src/pages/agents/TaskHistory.tsx
  • web/src/__tests__/utils/agents.property.test.ts
  • web/src/pages/agents/ActivityLog.tsx
  • web/src/pages/agents/AgentFilters.tsx
  • web/src/stores/agents.ts
  • web/src/hooks/useAgentsData.ts
  • web/src/hooks/useAgentDetailData.ts
  • web/src/api/types.ts
  • web/src/__tests__/stores/agents.test.ts
  • web/src/__tests__/utils/agents.test.ts
  • web/src/utils/agents.ts
web/src/pages/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • web/src/pages/AgentsPage.tsx
  • web/src/pages/agents/CareerTimelineEvent.tsx
  • web/src/pages/agents/ActivityLogItem.tsx
  • web/src/pages/agents/ToolBadges.tsx
  • web/src/pages/AgentDetailPage.tsx
  • web/src/pages/agents/CareerTimeline.tsx
  • web/src/pages/agents/TaskHistory.tsx
  • web/src/pages/agents/ActivityLog.tsx
  • web/src/pages/agents/AgentFilters.tsx
web/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • web/src/pages/AgentsPage.tsx
  • web/src/pages/agents/CareerTimelineEvent.tsx
  • web/src/pages/agents/ActivityLogItem.tsx
  • web/src/pages/agents/ToolBadges.tsx
  • web/src/pages/AgentDetailPage.tsx
  • web/src/pages/agents/CareerTimeline.tsx
  • web/src/pages/agents/TaskHistory.tsx
  • web/src/__tests__/utils/agents.property.test.ts
  • web/src/pages/agents/ActivityLog.tsx
  • web/src/pages/agents/AgentFilters.tsx
  • web/src/stores/agents.ts
  • web/src/hooks/useAgentsData.ts
  • web/src/hooks/useAgentDetailData.ts
  • web/src/api/types.ts
  • web/src/__tests__/stores/agents.test.ts
  • web/src/__tests__/utils/agents.test.ts
  • web/src/utils/agents.ts
web/**

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • web/src/pages/AgentsPage.tsx
  • web/src/pages/agents/CareerTimelineEvent.tsx
  • web/src/pages/agents/ActivityLogItem.tsx
  • web/src/pages/agents/ToolBadges.tsx
  • web/src/pages/AgentDetailPage.tsx
  • web/src/pages/agents/CareerTimeline.tsx
  • web/src/pages/agents/TaskHistory.tsx
  • web/src/__tests__/utils/agents.property.test.ts
  • web/src/pages/agents/ActivityLog.tsx
  • web/src/pages/agents/AgentFilters.tsx
  • web/src/stores/agents.ts
  • web/src/hooks/useAgentsData.ts
  • web/src/hooks/useAgentDetailData.ts
  • web/src/api/types.ts
  • web/src/__tests__/stores/agents.test.ts
  • web/src/__tests__/utils/agents.test.ts
  • web/src/utils/agents.ts
web/src/__tests__/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • web/src/__tests__/utils/agents.property.test.ts
  • web/src/__tests__/stores/agents.test.ts
  • web/src/__tests__/utils/agents.test.ts
web/src/stores/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • web/src/stores/agents.ts
docs/**/*.md

📄 CodeRabbit inference engine (CLAUDE.md)

Use Zensical for Markdown documentation build with mkdocs.yml config; docs in docs/ directory; design spec in docs/design/ (11 pages)

Files:

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

Applied to files:

  • web/src/pages/AgentsPage.tsx
  • web/src/pages/agents/CareerTimelineEvent.tsx
  • web/src/pages/agents/ActivityLogItem.tsx
  • web/src/pages/agents/ToolBadges.tsx
  • web/src/pages/AgentDetailPage.tsx
  • web/src/pages/agents/CareerTimeline.tsx
  • web/src/pages/agents/TaskHistory.tsx
  • web/src/pages/agents/ActivityLog.tsx
  • web/src/pages/agents/AgentFilters.tsx
  • web/src/hooks/useAgentsData.ts
  • docs/design/page-structure.md
  • web/src/utils/agents.ts
📚 Learning: 2026-03-27T09:44:40.059Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T09:44:40.059Z
Learning: Applies to web/src/**/*.{ts,tsx} : Do not recreate status dots inline; use `<StatusBadge>` component

Applied to files:

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

Applied to files:

  • web/src/pages/AgentsPage.tsx
  • web/src/pages/agents/CareerTimelineEvent.tsx
  • web/src/pages/agents/ActivityLogItem.tsx
  • web/src/pages/agents/ToolBadges.tsx
  • web/src/pages/agents/TaskHistory.tsx
  • web/src/pages/agents/AgentFilters.tsx
  • web/src/hooks/useAgentsData.ts
📚 Learning: 2026-03-15T21:20:09.993Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:20:09.993Z
Learning: Applies to web/src/components/** : Vue components organized by feature (agents/, approvals/, budget/, common/, dashboard/, layout/, messages/, org-chart/, tasks/).

Applied to files:

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

Applied to files:

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

Applied to files:

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

Applied to files:

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

Applied to files:

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

Applied to files:

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

Applied to files:

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

Applied to files:

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

Applied to files:

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

Applied to files:

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

Applied to files:

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

Applied to files:

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

Applied to files:

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

Applied to files:

  • web/src/api/types.ts
📚 Learning: 2026-03-16T06:24:56.341Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-16T06:24:56.341Z
Learning: Applies to docs/design/**/*.md : Design specification pages in `docs/design/` must be consulted before implementing features (7 pages: index, agents, organization, communication, engine, memory, operations)

Applied to files:

  • docs/design/page-structure.md
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to docs/design/*.md : Design spec pages: 7 pages in `docs/design/` — index, agents, organization, communication, engine, memory, operations

Applied to files:

  • docs/design/page-structure.md
📚 Learning: 2026-03-19T07:13:44.964Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:13:44.964Z
Learning: Always read the relevant `docs/design/` page before implementing any feature or planning any issue — DESIGN_SPEC.md is a pointer file linking to 7 design pages (Agents, Organization, Communication, Engine, Memory, Operations)

Applied to files:

  • docs/design/page-structure.md
📚 Learning: 2026-03-14T15:43:05.601Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-14T15:43:05.601Z
Learning: Applies to docs/** : Docs source in docs/ (Markdown, built with Zensical); design spec in docs/design/ (7 pages: index, agents, organization, communication, engine, memory, operations)

Applied to files:

  • docs/design/page-structure.md
📚 Learning: 2026-03-15T18:38:44.202Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:38:44.202Z
Learning: Always read the relevant `docs/design/` page before implementing any feature or planning any issue. DESIGN_SPEC.md is a pointer file linking to the 7 design pages (index, agents, organization, communication, engine, memory, operations).

Applied to files:

  • docs/design/page-structure.md
📚 Learning: 2026-03-18T08:23:08.912Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-18T08:23:08.912Z
Learning: When approved deviations occur, update the relevant `docs/design/` page to reflect the new reality.

Applied to files:

  • docs/design/page-structure.md
📚 Learning: 2026-03-17T22:08:13.456Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T22:08:13.456Z
Learning: Engine: Agent orchestration, execution loops, parallel execution, task decomposition, routing, task assignment, centralized single-writer task state engine (TaskEngine), task lifecycle, recovery, shutdown, workspace isolation, coordination (multi-agent pipeline: TopologyDispatcher protocol, 4 dispatchers — SAS/centralized/decentralized/context-dependent, wave execution, workspace lifecycle integration, CoordinationSectionConfig company config bridge, build_coordinator factory), coordination error classification, prompt policy validation, checkpoint recovery (checkpoint/, per-turn persistence, heartbeat detection, CheckpointRecoveryStrategy), approval gate (escalation detection, context parking/resume, EscalationInfo/ResumePayload models), stagnation detection (stagnation/, StagnationDetector protocol, ToolRepetitionDetector, dual-signal analysis, corrective prompt injection), agent runtime state (AgentRuntimeState, lightweight per-agent execution status for dashboard queries and recove...

Applied to files:

  • docs/design/page-structure.md
🪛 GitHub Check: Dashboard Lint
web/src/pages/agents/ToolBadges.tsx

[warning] 32-32:
Do not use item index in the array as its key

web/src/pages/agents/CareerTimeline.tsx

[warning] 25-25:
Do not use item index in the array as its key

web/src/pages/agents/ActivityLog.tsx

[warning] 41-41:
Do not use item index in the array as its key

🔇 Additional comments (11)
docs/design/page-structure.md (1)

67-82: LGTM! Agent Detail page model is now consistently documented.

The spec correctly propagates the full-page navigation model throughout: the Agents section (Lines 67–82), Overlays (Lines 149–152), URL Routing Map (Line 219), WebSocket subscription table (Lines 252–253), Controller-to-Page Map (Lines 327–328), and Design Principles (Lines 345, 348) all consistently describe /agents/{agentName} as a standalone page rather than a slide-in panel.

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

1-37: LGTM! Past review concerns addressed.

The ToolBadge component has been properly extracted (Lines 11–23), keeping the .map() block under the 8-line threshold. The key collision issue is resolved with key={\${tool}-${index}`}` (Line 32), which is appropriate here since tool names may be duplicated and no unique ID exists.

The static analysis warning about using index in keys is a false positive in this context—the index is combined with the tool name specifically to guarantee uniqueness when duplicate tool names exist, and the list order is stable.

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

13-36: LGTM! Key uniqueness strengthened as requested.

The key now includes the array index (Line 25: key={\${event.event_type}-${event.timestamp}-${i}`}`), addressing the previous review concern about potential collisions when events share the same type and timestamp.

The static analysis warning is a false positive here—CareerEvent has no unique ID field, so including the index is the correct approach to guarantee key uniqueness.

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

9-26: LGTM! Semantic timestamp element implemented.

The timestamp now uses the semantic <time> element with dateTime={event.timestamp} (Lines 18–23), improving accessibility and enabling structured parsing by browsers and assistive technologies.

The icon handling is correct—getActivityEventIcon returns a LucideIcon component reference (per web/src/utils/agents.ts:229-250), which is properly invoked as <Icon ... /> with aria-hidden="true".

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

11-57: LGTM! Token-based spacing applied.

The hardcoded left-[7px] has been replaced with the Tailwind spacing token left-1.5 (Line 18), aligning with the design token requirements.

The color handling is type-safe—getCareerEventColor returns exactly the four SemanticColor values (success, accent, warning, danger) per the type definition in web/src/lib/utils.ts:16-19, and all four variants are properly handled in the cn() calls for both the dot (Lines 25–28) and label styling (Lines 38–41).

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

57-145: LGTM! Stale response and pagination cap issues addressed.

The stale response concern is resolved with the _detailRequestName guard (Lines 57–58, 100, 113, 142), which ensures that slow responses from previous agent selections don't overwrite current detail data.

The activity pagination cap issue is fixed:

  • Line 150 short-circuits if already at MAX_ACTIVITIES
  • Line 156 ignores responses if the agent changed during fetch
  • Line 161 clamps activityTotal to MAX_ACTIVITIES, preventing the UI from offering "load more" when the cap is reached
web/src/pages/agents/ActivityLog.tsx (1)

16-49: LGTM! Key collision issue addressed.

The composite key now includes the array index (Line 41: key={\${event.event_type}-${event.timestamp}-${index}`}), ensuring uniqueness since AgentActivityEventhas noid` field.

The static analysis warning is a false positive—without a unique identifier on the event type, including the index is the correct approach to guarantee key stability.

The pagination logic is correct: hasMore properly compares current count against total, and the "Load more" button only appears when more data is available.

web/src/pages/AgentsPage.tsx (4)

17-19: Solid first-load handling with skeleton gate.

The loading && totalAgents === 0 guard avoids empty/list flicker and gives a clean initial UX.


30-39: Accessible error announcement is correctly implemented.

Using role="alert" with aria-live="assertive" on dynamic error content is correct and production-safe.

As per coding guidelines, dynamic web UI should preserve accessibility and tokenized styling.


41-50: WebSocket disconnect banner semantics look correct.

role="status" with polite live region behavior is appropriate for non-blocking connectivity updates.


52-53: Good page composition and separation of concerns.

Keeping filters and grid in page-scoped subcomponents keeps this page lean and maintainable.

As per coding guidelines, page-scoped sub-components should live under the page directory structure.

const VALID_DEPARTMENTS = new Set<string>(DEPARTMENT_NAME_VALUES)
const VALID_LEVELS = new Set<string>(SENIORITY_LEVEL_VALUES)
const VALID_STATUSES = new Set<string>(AGENT_STATUS_VALUES)
const VALID_SORT_KEYS = new Set<string>(['name', 'department', 'level', 'status', 'hiring_date'])
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

The list still cannot sort by performance, cost, or activity.

Issue #779 scopes those sort modes for this page, but this component hard-codes only five keys in both VALID_SORT_KEYS and the <select>. As written, users cannot access the required sorts, and Line 18 will reject them even if they are added elsewhere.

Also applies to: 96-110

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

In `@web/src/pages/agents/AgentFilters.tsx` at line 18, VALID_SORT_KEYS in
AgentFilters.tsx currently hard-codes only
['name','department','level','status','hiring_date'] and the corresponding
<select> options, which blocks the new sort modes; update the VALID_SORT_KEYS
Set to include 'performance', 'cost', and 'activity', and add matching option
entries to the component's sort <select> (the same select currently rendering
options around the block handling sort modes) so those keys are accepted and
selectable by the UI; keep the set and the select options in sync to avoid
rejected sorts.

@Aureliolo Aureliolo temporarily deployed to cloudflare-preview March 27, 2026 12:21 — 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: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@web/src/stores/agents.ts`:
- Around line 58-60: The module-scoped _detailRequestName token isn't cleared by
clearDetail(), so late in-flight responses can repopulate a cleared store;
update clearDetail() to reset the staleness token or (preferred) add a monotonic
requestId to the AgentsState and increment it for each detail request, capture
the current requestId when starting fetch, and compare that requestId before
every set() that writes detail (rejecting stale responses); locate usages of
_detailRequestName and the function clearDetail(), and update the fetch-detail
flow to check the requestId (or cleared token) before mutating state.
- Around line 105-111: fetchAgentDetail() currently always replaces the activity
buffer with page 1 (limit:20), which discards any pages previously appended by
fetchMoreActivity(); change the refresh behavior so that when the fetched agent
name matches the current agent in state you merge/prepend the new activity page
into the existing activity array (e.g., in the code handling the
Promise.allSettled results for getAgentActivity/getAgentHistory), deduplicating
by a unique id and keeping the existing appended pages intact, and update
activityTotal from the response but do not drop appended items; apply the same
merge/prepend logic to the similar block around the other fetch (lines 131-136)
to ensure background refreshes don't reset paginated activity.
- Around line 87-95: fetchAgents currently only requests the first 200 agents
via listAgents({ limit: 200 }) and then performs search/filter/sort client-side,
causing missed results when totalAgents > 200; fix by either (A) exhausting
server pagination inside fetchAgents — call listAgents repeatedly (using limit
and an offset/page token returned by the API or incrementing an offset) until
you've fetched result.total or until no more pages and then set agents,
totalAgents, listLoading/listError accordingly, or (B) move search/filter/sort
to the server: change fetchAgents to accept query/sort/filter params and pass
them to listAgents so the server returns the correct subset (and update callers
to pass those params) — update references to fetchAgents, listAgents, agents,
and totalAgents to reflect the chosen approach and ensure listLoading/listError
are handled for the multi-request flow.

In `@web/src/utils/agents.ts`:
- Around line 73-77: Normalize the incoming search string in the agents filter
by trimming whitespace before lowercasing and matching: replace the current use
of filters.search -> q with a trimmed+lowercased value (e.g., const q =
filters.search.trim().toLowerCase()) and if the trimmed q is an empty string,
skip the search branch entirely; then use q in the result.filter predicate that
checks a.name.toLowerCase() and a.role.toLowerCase() so padded queries like '
Alice ' will match correctly.
🪄 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: 07e82730-1f08-495f-89f6-cc29f9c261b3

📥 Commits

Reviewing files that changed from the base of the PR and between 0809c4e and 55b7b6f.

📒 Files selected for processing (7)
  • web/src/__tests__/stores/agents.test.ts
  • web/src/__tests__/utils/agents.property.test.ts
  • web/src/__tests__/utils/agents.test.ts
  • web/src/hooks/useAgentDetailData.ts
  • web/src/pages/agents/TaskHistory.tsx
  • web/src/stores/agents.ts
  • web/src/utils/agents.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: Build Web
  • GitHub Check: Build Sandbox
  • GitHub Check: Build Backend
  • GitHub Check: Dependency Review
  • GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • web/src/pages/agents/TaskHistory.tsx
  • web/src/__tests__/utils/agents.property.test.ts
  • web/src/utils/agents.ts
  • web/src/stores/agents.ts
  • web/src/hooks/useAgentDetailData.ts
  • web/src/__tests__/utils/agents.test.ts
  • web/src/__tests__/stores/agents.test.ts
web/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • web/src/pages/agents/TaskHistory.tsx
  • web/src/__tests__/utils/agents.property.test.ts
  • web/src/utils/agents.ts
  • web/src/stores/agents.ts
  • web/src/hooks/useAgentDetailData.ts
  • web/src/__tests__/utils/agents.test.ts
  • web/src/__tests__/stores/agents.test.ts
web/src/pages/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • web/src/pages/agents/TaskHistory.tsx
web/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • web/src/pages/agents/TaskHistory.tsx
  • web/src/__tests__/utils/agents.property.test.ts
  • web/src/utils/agents.ts
  • web/src/stores/agents.ts
  • web/src/hooks/useAgentDetailData.ts
  • web/src/__tests__/utils/agents.test.ts
  • web/src/__tests__/stores/agents.test.ts
web/**

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • web/src/pages/agents/TaskHistory.tsx
  • web/src/__tests__/utils/agents.property.test.ts
  • web/src/utils/agents.ts
  • web/src/stores/agents.ts
  • web/src/hooks/useAgentDetailData.ts
  • web/src/__tests__/utils/agents.test.ts
  • web/src/__tests__/stores/agents.test.ts
web/src/__tests__/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • web/src/__tests__/utils/agents.property.test.ts
  • web/src/__tests__/utils/agents.test.ts
  • web/src/__tests__/stores/agents.test.ts
web/src/stores/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • web/src/stores/agents.ts
🧠 Learnings (6)
📓 Common learnings
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-16T06:24:56.341Z
Learning: Applies to docs/design/**/*.md : Design specification pages in `docs/design/` must be consulted before implementing features (7 pages: index, agents, organization, communication, engine, memory, operations)
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T09:44:40.059Z
Learning: Applies to web/src/stores/**/*.{ts,tsx} : Use Zustand stores in web dashboard for state management (auth, WebSocket, toast, analytics, domain shells)
📚 Learning: 2026-03-27T09:44:40.059Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T09:44:40.059Z
Learning: Applies to web/src/**/*.{ts,tsx} : Always reuse existing components from `web/src/components/ui/` (StatusBadge, MetricCard, Sparkline, SectionCard, AgentCard, DeptHealthBar, ProgressGauge, StatPill, Avatar, Button, Toast, Skeleton, EmptyState, ErrorBoundary, ConfirmDialog, CommandPalette, InlineEdit, AnimatedPresence, StaggerGroup/StaggerItem) before creating new ones

Applied to files:

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

Applied to files:

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

Applied to files:

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

Applied to files:

  • web/src/stores/agents.ts
  • web/src/__tests__/stores/agents.test.ts
🔇 Additional comments (4)
web/src/pages/agents/TaskHistory.tsx (2)

15-27: Robust timestamp handling in duration computation.

The created_at filtering plus updated_at fallback logic correctly prevents NaN from propagating into bar scaling.


30-45: Good reuse of shared UI primitives in the task-history section.

This keeps the page aligned with existing dashboard patterns and avoids custom one-off layout primitives.

Based on learnings: Always reuse existing components from web/src/components/ui/ before creating new ones.

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

90-104: Confirm useWebSocket({ bindings: [] }) is a true no-op.

The fetch/poll guards are in place, but this hook still instantiates useWebSocket when agentName is empty. If the hook connects regardless of binding count, the missing-route case still opens a live socket. Expect either an explicit enabled option or an early return before any connection setup when bindings.length === 0.

#!/bin/bash
set -euo pipefail

FILE="$(fd -t f 'useWebSocket\.(ts|tsx)$' web/src/hooks | head -n 1)"
printf 'Inspecting %s\n\n' "$FILE"
rg -n -C4 'export function useWebSocket|interface .*WebSocket|type .*WebSocket|enabled|bindings|new WebSocket|connect|close' "$FILE"
web/src/__tests__/utils/agents.test.ts (1)

299-319: Make these currency assertions locale-agnostic.

formatCostPerTask() is driven by Intl.NumberFormat, which produces locale-specific output (e.g., 0,35 $US in fr-FR vs. $0.35 in en-US). Assertions checking for literal strings '0.35', '12.50', and the pattern /\$/ will fail across different locales. Use locale-agnostic matchers (e.g., checking for digit presence and absence of locale-specific separators) or compare against a formatter with an explicit locale.

Comment on lines +87 to +95
fetchAgents: async () => {
set({ listLoading: true, listError: null })
try {
const result = await listAgents({ limit: 200 })
set({
agents: result.data,
totalAgents: result.total,
listLoading: false,
})
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

Client-side list interactions break once there are more than 200 agents.

fetchAgents() only loads the first 200 rows, but search/filter/sort are all performed locally. After the dataset grows past that cap, valid matches outside the first page can never appear even though totalAgents still reports them. Either exhaust pagination here or move those controls server-side.

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

In `@web/src/stores/agents.ts` around lines 87 - 95, fetchAgents currently only
requests the first 200 agents via listAgents({ limit: 200 }) and then performs
search/filter/sort client-side, causing missed results when totalAgents > 200;
fix by either (A) exhausting server pagination inside fetchAgents — call
listAgents repeatedly (using limit and an offset/page token returned by the API
or incrementing an offset) until you've fetched result.total or until no more
pages and then set agents, totalAgents, listLoading/listError accordingly, or
(B) move search/filter/sort to the server: change fetchAgents to accept
query/sort/filter params and pass them to listAgents so the server returns the
correct subset (and update callers to pass those params) — update references to
fetchAgents, listAgents, agents, and totalAgents to reflect the chosen approach
and ensure listLoading/listError are handled for the multi-request flow.

Comment on lines +105 to +111
const [agentResult, perfResult, tasksResult, activityResult, historyResult] =
await Promise.allSettled([
getAgent(name),
getAgentPerformance(name),
listTasks({ assigned_to: name, limit: 50 }),
getAgentActivity(name, { limit: 20 }),
getAgentHistory(name),
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

Background refreshes are discarding already-paginated activity.

fetchAgentDetail() always re-requests page 1 (limit: 20) and then replaces activity with that first page. Since useAgentDetailData() polls and refreshes on WebSocket events, any pages appended by fetchMoreActivity() disappear on the next refresh, and activityTotal jumps back to the raw backend total. For same-agent refreshes, merge/prepend the latest page into the existing buffer instead of resetting it.

Also applies to: 131-136

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

In `@web/src/stores/agents.ts` around lines 105 - 111, fetchAgentDetail()
currently always replaces the activity buffer with page 1 (limit:20), which
discards any pages previously appended by fetchMoreActivity(); change the
refresh behavior so that when the fetched agent name matches the current agent
in state you merge/prepend the new activity page into the existing activity
array (e.g., in the code handling the Promise.allSettled results for
getAgentActivity/getAgentHistory), deduplicating by a unique id and keeping the
existing appended pages intact, and update activityTotal from the response but
do not drop appended items; apply the same merge/prepend logic to the similar
block around the other fetch (lines 131-136) to ensure background refreshes
don't reset paginated activity.

@Aureliolo Aureliolo temporarily deployed to cloudflare-preview March 27, 2026 12:34 — 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

♻️ Duplicate comments (3)
web/src/stores/agents.ts (3)

87-95: ⚠️ Potential issue | 🟠 Major

The list page stops being correct after the first 200 agents.

fetchAgents() only loads limit: 200, but search/filter/sort are all client-side. Once the backend has more than 200 agents, valid matches outside that first page can never be surfaced even though totalAgents says they exist. Either exhaust pagination here or move those controls server-side.

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

In `@web/src/stores/agents.ts` around lines 87 - 95, fetchAgents currently
requests only the first 200 agents (using listAgents({ limit: 200 })) while
search/filter/sort are done client-side, so matches beyond that page are never
visible; update fetchAgents to either (A) exhaustively page through the backend
by repeatedly calling listAgents with offset/page parameters until you've
retrieved totalAgents (accumulating into the agents array and updating
listLoading/listError appropriately) or (B) switch search/filter/sort to
server-side by passing filter/sort/search params to listAgents and relying on
paginated responses; locate and update the fetchAgents function and any related
state setters (agents, totalAgents, listLoading, listError) to implement the
chosen approach.

58-59: ⚠️ Potential issue | 🔴 Critical

Use a per-request token for detail refreshes, not just the agent name.

_detailRequestName only changes when the route changes. Polling/WebSocket refreshes can overlap fetchAgentDetail(name) calls for the same agent, so both responses pass this guard and the slower older snapshot can overwrite the newer one. Track a monotonic request id (or abort the previous request) and compare that before every set().

Also applies to: 101-115, 143-145

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

In `@web/src/stores/agents.ts` around lines 58 - 59, The current guard uses the
module-level _detailRequestName which only changes on route change, allowing
concurrent fetchAgentDetail(name) calls for the same agent to race and let older
responses overwrite newer state; switch to a per-request token or monotonic
request id: in fetchAgentDetail (and where responses call set()), create a new
local requestId (or increment a module-level _detailRequestId) before
dispatching the async request, attach that id to the request context, and check
that id matches the latest recorded id before calling set() (or alternatively
abort the previous request via AbortController). Update all places that compare
_detailRequestName (including the blocks around lines where set() is called) to
use this request id token to prevent stale overwrites.

124-141: ⚠️ Potential issue | 🟠 Major

Same-agent refreshes are erasing already-loaded detail data.

fetchAgentDetail() is also used for background refreshes. In this block, any rejected secondary request is rewritten to null/[], and a fulfilled activity request always replaces the buffer with page 1. A transient /performance or /history failure therefore blanks previously rendered sections, and any successful refresh discards activity pages loaded via fetchMoreActivity(). Keep the previous slice on secondary failure, and merge/dedupe the latest activity page instead of overwriting it.

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

In `@web/src/stores/agents.ts` around lines 124 - 141, fetchAgentDetail is
overwriting previously-loaded secondary data on partial failures and always
replacing activity pages; change the set call to use the functional form (prev
=> ({...})) so you read previous state and only replace fields whose
corresponding promise fulfilled: set performance only if perfResult.status ===
'fulfilled', agentTasks only if tasksResult.status === 'fulfilled',
careerHistory only if historyResult.status === 'fulfilled', and leave existing
values otherwise; for activity, when activityResult.status === 'fulfilled' merge
the returned page into prev.activity (concat and dedupe by the activity item
unique id) and update activityTotal from activityResult.value.total, but if
activityResult.status === 'rejected' keep prev.activity and prev.activityTotal;
keep setting selectedAgent, detailLoading and detailError as now but build
detailError from partialErrors without clearing previously-loaded data on
rejected secondary requests.
🤖 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/utils/agents.ts`:
- Around line 147-177: computePerformanceCards currently only sets sparklineData
for TASKS COMPLETED; update it to populate sparkline arrays for the other three
cards when perf.windows.length >= 2 by mapping the appropriate window fields:
for 'AVG COMPLETION TIME' build avgSparkline = perf.windows.map(w =>
w.avg_completion_time_seconds), for 'SUCCESS RATE' build successSparkline =
perf.windows.map(w => w.success_rate_percent), and for 'COST PER TASK' build
costSparkline = perf.windows.map(w => w.cost_per_task_usd); then pass these
arrays as sparklineData on their respective card objects (same length/condition
as taskSparkline).

---

Duplicate comments:
In `@web/src/stores/agents.ts`:
- Around line 87-95: fetchAgents currently requests only the first 200 agents
(using listAgents({ limit: 200 })) while search/filter/sort are done
client-side, so matches beyond that page are never visible; update fetchAgents
to either (A) exhaustively page through the backend by repeatedly calling
listAgents with offset/page parameters until you've retrieved totalAgents
(accumulating into the agents array and updating listLoading/listError
appropriately) or (B) switch search/filter/sort to server-side by passing
filter/sort/search params to listAgents and relying on paginated responses;
locate and update the fetchAgents function and any related state setters
(agents, totalAgents, listLoading, listError) to implement the chosen approach.
- Around line 58-59: The current guard uses the module-level _detailRequestName
which only changes on route change, allowing concurrent fetchAgentDetail(name)
calls for the same agent to race and let older responses overwrite newer state;
switch to a per-request token or monotonic request id: in fetchAgentDetail (and
where responses call set()), create a new local requestId (or increment a
module-level _detailRequestId) before dispatching the async request, attach that
id to the request context, and check that id matches the latest recorded id
before calling set() (or alternatively abort the previous request via
AbortController). Update all places that compare _detailRequestName (including
the blocks around lines where set() is called) to use this request id token to
prevent stale overwrites.
- Around line 124-141: fetchAgentDetail is overwriting previously-loaded
secondary data on partial failures and always replacing activity pages; change
the set call to use the functional form (prev => ({...})) so you read previous
state and only replace fields whose corresponding promise fulfilled: set
performance only if perfResult.status === 'fulfilled', agentTasks only if
tasksResult.status === 'fulfilled', careerHistory only if historyResult.status
=== 'fulfilled', and leave existing values otherwise; for activity, when
activityResult.status === 'fulfilled' merge the returned page into prev.activity
(concat and dedupe by the activity item unique id) and update activityTotal from
activityResult.value.total, but if activityResult.status === 'rejected' keep
prev.activity and prev.activityTotal; keep setting selectedAgent, detailLoading
and detailError as now but build detailError from partialErrors without clearing
previously-loaded data on rejected secondary requests.
🪄 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: b20a30a1-6a79-485b-8af4-3a4e8dfc1a3d

📥 Commits

Reviewing files that changed from the base of the PR and between 55b7b6f and a222c73.

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

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • web/src/utils/agents.ts
  • web/src/stores/agents.ts
web/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • web/src/utils/agents.ts
  • web/src/stores/agents.ts
web/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • web/src/utils/agents.ts
  • web/src/stores/agents.ts
web/**

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • web/src/utils/agents.ts
  • web/src/stores/agents.ts
web/src/stores/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • web/src/stores/agents.ts
🧠 Learnings (4)
📓 Common learnings
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:20:09.993Z
Learning: Applies to web/src/components/** : Vue components organized by feature (agents/, approvals/, budget/, common/, dashboard/, layout/, messages/, org-chart/, tasks/).
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-16T06:24:56.341Z
Learning: Applies to docs/design/**/*.md : Design specification pages in `docs/design/` must be consulted before implementing features (7 pages: index, agents, organization, communication, engine, memory, operations)
📚 Learning: 2026-03-27T09:44:40.059Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T09:44:40.059Z
Learning: Applies to web/src/**/*.{ts,tsx} : Always reuse existing components from `web/src/components/ui/` (StatusBadge, MetricCard, Sparkline, SectionCard, AgentCard, DeptHealthBar, ProgressGauge, StatPill, Avatar, Button, Toast, Skeleton, EmptyState, ErrorBoundary, ConfirmDialog, CommandPalette, InlineEdit, AnimatedPresence, StaggerGroup/StaggerItem) before creating new ones

Applied to files:

  • web/src/utils/agents.ts
📚 Learning: 2026-03-15T21:20:09.993Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:20:09.993Z
Learning: Applies to web/src/components/** : Vue components organized by feature (agents/, approvals/, budget/, common/, dashboard/, layout/, messages/, org-chart/, tasks/).

Applied to files:

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

Applied to files:

  • web/src/stores/agents.ts

Aureliolo and others added 6 commits March 27, 2026 13:49
Implement the Agent Profiles list page and Agent Detail page with
biography-style profiles including career arcs, performance metrics,
and prose alongside numbers.

List page:
- Responsive grid of AgentCards with filtering (department, level, status),
  search by name/role, and sorting (name, department, level, hire date)
- Client-side filtering with persisted filter state in Zustand store
- Polling + WebSocket subscriptions for real-time updates

Detail page:
- Identity header: large avatar, name, role, status badge with pulse,
  department/level/autonomy StatPills
- Performance metrics: 2x2 MetricCard grid (tasks, time, success, cost)
  with sparklines from window data
- Prose insights: generated sentences from performance data
- Tool badges: horizontal flex-wrap of permitted tools
- Career timeline: vertical timeline with colored dots per event type
- Task history: Gantt-style horizontal bars with duration labels
- Activity log: paginated chronological event list with type icons

New types: AgentPerformanceSummary, WindowMetrics, TrendResult,
TrendDirection, AgentActivityEvent, CareerEvent, CareerEventType

Closes #779

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Update docs/design/page-structure.md: agent detail is a full page
  (not slide-in overlay), single-scroll layout (not tabbed), updated
  API endpoints and WS channels, note deferred Access tab
- Update CLAUDE.md: stores and hooks descriptions reflect new patterns
- Add Readonly<Record<>> to AgentActivityEvent.related_ids and
  CareerEvent.metadata for immutability consistency
- Add JSDoc to WindowMetrics documenting server-side invariant
- Add console.warn to fetchMoreActivity silent catch
- Add 10 new tests: MAX_ACTIVITIES cap, silent failure preservation,
  setSortDirection, partial failure combos, sort by level/status,
  declining trend insight, quality threshold, 60s boundary,
  negative cost behavior

Pre-reviewed by 6 agents, 17 findings addressed

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

Docs: fix 5 stale slide-in panel references in page-structure.md,
add WS subscription for detail page tasks channel.

Store: add staleness guard for rapid agent navigation, surface partial
errors from Promise.allSettled, clamp activity pagination cap, use
getErrorMessage instead of raw err in console.warn.

Utils: semantic sort ordering for level/status fields (not lexicographic),
use formatCurrency (EUR) instead of hardcoded $ prefix, document unused
_agent parameter in generateInsights.

UI: replace hardcoded left-[7px] with token, wrap ProseInsight in
ErrorBoundary, extract ToolBadge from map, use <time> for timestamps,
add aria-live to error/warning banners, validate select values at runtime,
add eslint-disable explanations, fix React key collisions.

Tests: strengthen error assertions, fix masked activityTotal test, add
sparkline undefined test, add status sort key to property test, fix
property test invariants, verify combined filter identity.

Types: fix AgentConfig JSDoc, validate dates in TaskHistory sort.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fix formatCostPerTask to pass USD (field is cost_per_task_usd, not EUR)
- Make property test currency assertion format-agnostic (digits + symbol)
- Add activityLoading flag to store to prevent duplicate pagination requests
- Guard useAgentDetailData against empty agentName (skip fetch/polling/WS)
- Validate updated_at before computing TaskHistory bar durations (NaN guard)
- Update cost test assertions to match USD formatting

Skipped: sort key expansion (performance/cost/activity) -- AgentSortKey type
does not include those values, list API has no performance data, and the
design spec was intentionally updated to reflect current API capabilities.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Reset _detailRequestName in clearDetail() so in-flight fetchAgentDetail
  responses are rejected when navigating away from the detail page
- Trim whitespace from search query before matching so pasted text with
  leading/trailing spaces still finds results

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Previously only TASKS COMPLETED had a sparkline. Now all cards derive
sparkline data from WindowMetrics when 2+ windows exist:
- AVG COMPLETION TIME: avg_completion_time_seconds per window
- SUCCESS RATE: success_rate per window (scaled to percentage)
- COST PER TASK: avg_cost_per_task per window

Nullable window fields fall back to 0 for sparkline rendering.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@Aureliolo Aureliolo force-pushed the feat/agent-profiles-page branch from a222c73 to 9dbc51b Compare March 27, 2026 12:50
@Aureliolo Aureliolo temporarily deployed to cloudflare-preview March 27, 2026 12:51 — with GitHub Actions Inactive
@Aureliolo
Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 27, 2026

✅ Actions performed

Review triggered.

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

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 12

♻️ Duplicate comments (6)
web/src/pages/agents/ActivityLog.tsx (1)

39-44: ⚠️ Potential issue | 🟡 Minor

Drop the index from the React key.

This log supports live updates, so prepending a new event changes every -${index} suffix and remounts the rest of the list. Use a key derived only from immutable event payload, or better, expose a stable id on AgentActivityEvent.

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

In `@web/src/pages/agents/ActivityLog.tsx` around lines 39 - 44, The list key
currently uses a mutable index which causes unnecessary remounts; update the map
key in the StaggerItem within the events.map to use a stable identifier from the
event itself (e.g., event.id) instead of `${...}-${index}`—if AgentActivityEvent
does not yet expose id, add a stable id property to AgentActivityEvent (or
derive a deterministic key from immutable fields like event_type and timestamp)
and use that value as the key for StaggerItem and ActivityLogItem so keys remain
stable across live prepends.
web/src/pages/agents/AgentIdentityHeader.stories.tsx (1)

30-34: ⚠️ Potential issue | 🟡 Minor

Add the required Storybook a11y test setting.

This meta object still omits parameters.a11y.test. As per coding guidelines: web/src/**/*.stories.tsx: use parameters.a11y.test: 'error' | 'todo' | 'off' for accessibility testing.

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

In `@web/src/pages/agents/AgentIdentityHeader.stories.tsx` around lines 30 - 34,
The Storybook meta for AgentIdentityHeader is missing the required accessibility
test setting; update the meta object (the constant named "meta" for component
AgentIdentityHeader) to include a parameters.a11y.test property set to one of
'error' | 'todo' | 'off' (choose the appropriate value for this story),
preserving existing fields like title and decorators so Storybook picks up the
a11y rule.
web/src/pages/agents/AgentFilters.stories.tsx (1)

6-27: ⚠️ Potential issue | 🟡 Minor

Add the required Storybook a11y test setting.

This meta object still omits parameters.a11y.test. As per coding guidelines: web/src/**/*.stories.tsx: use parameters.a11y.test: 'error' | 'todo' | 'off' for accessibility testing.

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

In `@web/src/pages/agents/AgentFilters.stories.tsx` around lines 6 - 27, The
Storybook meta for AgentFilters is missing the required accessibility test
setting; update the meta object (the constant named meta) to include a
parameters property with a11y.test set to one of 'error' | 'todo' | 'off' (e.g.,
parameters: { a11y: { test: 'error' } }) so Storybook will run/record a11y
checks for the AgentFilters story; ensure this change sits alongside the
existing title/component/decorators entries in the meta object.
web/src/stores/agents.ts (3)

105-112: ⚠️ Potential issue | 🟠 Major

Detail refreshes still drop previously paginated activity.

Every fetchAgentDetail() replaces activity with the newest first page. Because web/src/hooks/useAgentDetailData.ts polls and refreshes on WebSocket events, any rows appended by fetchMoreActivity() disappear on the next refresh. When selectedAgent?.name === name, merge/prepend page 1 into the existing buffer and dedupe instead of resetting it.

Also applies to: 131-136

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

In `@web/src/stores/agents.ts` around lines 105 - 112, fetchAgentDetail currently
overwrites the activity buffer with the newest first page on every refresh,
which causes rows appended by fetchMoreActivity() to be lost; update
fetchAgentDetail (the Promise.allSettled block that assigns activity) so that
when selectedAgent?.name === name you merge/prepend the freshly fetched page 1
into the existing activity buffer instead of replacing it and dedupe entries (by
unique id/timestamp) to avoid duplicates; apply the same merge behavior to the
second occurrence noted (lines ~131-136) so both refresh paths preserve
paginated items appended by fetchMoreActivity().

58-60: ⚠️ Potential issue | 🟠 Major

The staleness guard still loses same-agent refresh races.

_detailRequestName only changes when the route changes. If polling or a WebSocket event starts a second fetchAgentDetail('Alice Smith') before the first resolves, the older response still passes the name check and can overwrite fresher data. Use a monotonic request id (or cancellation) and compare that token before every set(), including the error path.

🛡️ Minimal request-id sketch
-// Track the latest requested agent name to prevent stale responses from overwriting
-let _detailRequestName = ''
+// Track the latest detail request so slower same-agent refreshes cannot win
+let _detailRequestId = 0

  fetchAgentDetail: async (name: string) => {
-   _detailRequestName = name
+   const requestId = ++_detailRequestId
    set({ detailLoading: true, detailError: null })
    try {
      const [agentResult, perfResult, tasksResult, activityResult, historyResult] =
        await Promise.allSettled([
          getAgent(name),
          getAgentPerformance(name),
          listTasks({ assigned_to: name, limit: 50 }),
          getAgentActivity(name, { limit: 20 }),
          getAgentHistory(name),
        ])

-     if (_detailRequestName !== name) return
+     if (requestId !== _detailRequestId) return

      ...
    } catch (err) {
-     if (_detailRequestName !== name) return
+     if (requestId !== _detailRequestId) return
      set({ detailLoading: false, detailError: getErrorMessage(err) })
    }
  },

  clearDetail: () => {
-   _detailRequestName = ''
+   _detailRequestId++

Also applies to: 101-145, 186-188

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

In `@web/src/stores/agents.ts` around lines 58 - 60, The current staleness guard
_detailRequestName only changes on route change and fails when multiple requests
for the same agent overlap; replace it with a monotonic request token: add a
numeric _detailRequestId that you increment each time fetchAgentDetail is
invoked, capture the current id in the local scope of the request, and before
every state mutation (every set() call and error path) compare the captured id
to the latest _detailRequestId and bail if they differ; update the logic inside
fetchAgentDetail (and any related handlers around the existing set() calls and
error handling referenced in the diff) to use this request-id check so older
responses cannot overwrite newer ones.

87-95: ⚠️ Potential issue | 🟠 Major

Client-side list controls still stop at the first 200 agents.

fetchAgents() only loads one page, but the list page’s search/filter/sort are performed in-memory. Once result.total exceeds 200, valid matches outside the first page can never appear even though totalAgents says they exist. Either exhaust pagination here or push those controls down to listAgents().

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

In `@web/src/stores/agents.ts` around lines 87 - 95, fetchAgents currently only
requests the first page (limit: 200) via listAgents, which causes client-side
search/filter/sort over only that page; update fetchAgents to exhaust pagination
by repeatedly calling listAgents with an offset/page token (or increasing page
number) until you have fetched result.total items and append each page's
result.data to state.agents, then set totalAgents and clear
listLoading/listError, or alternatively move filtering/sorting into listAgents
so the server returns filtered results; target the fetchAgents function and its
use of listAgents/result.total/result.data when implementing the change.
🤖 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__/stores/agents.test.ts`:
- Around line 143-209: Add two new tests covering live-refresh race and re-run
after pagination: (1) for fetchAgentDetail, call
useAgentsStore.getState().fetchAgentDetail('Alice') twice but control mocked
getAgent/getAgentPerformance/getAgentActivity/getAgentHistory with deferred
promises so the first call's promises resolve after the second; then assert the
store's selectedAgent/performance/detailError reflect the second call's results
(verify no stale overwrite). (2) for fetchMoreActivity, mock initial
fetchAgentDetail to return a first page of activity, then call
useAgentsStore.getState().fetchMoreActivity() which appends older pages (mock
listTasks/getAgentActivity accordingly), then trigger fetchAgentDetail('Alice')
again and assert the second fetch runs and replaces/merges activity correctly
(ensure agentTasks/careerHistory reflect the re-fetched data and detailError is
updated). Use the existing helpers makeAgent/makePerformance and vi.mocked with
controllable deferred promises to force ordering and to simulate failures as
needed.

In `@web/src/__tests__/utils/agents.property.test.ts`:
- Around line 104-119: The arbitrary arbPerformance currently allows
tasks_completed_7d and tasks_completed_30d to be generated independently which
can produce impossible states (e.g., tasks_completed_7d > tasks_completed_30d);
modify arbPerformance so that after choosing total you generate
tasks_completed_30d as an integer up to min(total,500) and then generate
tasks_completed_7d with a max of tasks_completed_30d (or
min(tasks_completed_30d,100)), ensuring tasks_completed_7d <=
tasks_completed_30d <= total; locate the logic in arbPerformance and update the
chain to produce dependent values for tasks_completed_30d and tasks_completed_7d
rather than independent fc.nat calls.

In `@web/src/hooks/useAgentDetailData.ts`:
- Around line 91-105: The current WebSocket bindings in useAgentDetailData.ts
call fetchAgentDetail(agentName) on every global agents/tasks event, causing
noisy reloads; update the ChannelBinding creation (where DETAIL_CHANNELS is
mapped and useWebSocket is called) to either pass an agent-specific filters
option into useWebSocket (so only events for the current agent are delivered) or
keep bindings unchanged but change each handler to inspect the event payload and
return early if the payload.agentName (or id) does not match the local agentName
before calling fetchAgentDetail; ensure you reference the existing
DETAIL_CHANNELS mapping and the fetchAgentDetail call so the check/filter is
applied only for the current agent.

In `@web/src/hooks/useAgentsData.ts`:
- Around line 53-63: The current bindings call
useAgentsStore.getState().fetchAgents() for every AGENT_CHANNELS event causing
redundant API calls; wrap that handler with a debounced refresher (e.g.,
createDebouncedFetch or use a lodash debounce) so rapid events trigger a single
fetch. Update the binding handler in the bindings array (the object with channel
and handler) to call the debounced function instead of fetchAgents directly,
ensure the debounced function is created once (useRef or module-level singleton)
and cleaned up if needed to avoid leaks.

In `@web/src/pages/AgentDetailPage.tsx`:
- Around line 17-33: The page can briefly render the previous agent while
refetching; update the render guard in AgentDetailPage to also verify that the
loaded agent matches the current route param (agentName) or ensure
useAgentDetailData clears the detail when agentName changes: specifically,
modify the existing guard that returns AgentDetailSkeleton (currently testing
loading && !agent) to also check agent?.name (or the equivalent selectedAgent
id) against agentName, or add logic in useAgentDetailData to reset selectedAgent
to null when agentName changes so /agents/Bob never paints Alice's profile.

In `@web/src/pages/agents/ActivityLog.stories.tsx`:
- Around line 17-21: The meta object for the ActivityLog story is missing the
required Storybook accessibility test setting; update the exported meta (the
const meta defined for ActivityLog) to include a parameters object with an a11y
property and set test to one of the allowed values ('error' | 'todo' | 'off') so
the story respects repo accessibility rules (e.g., add parameters: { a11y: {
test: 'error' } } to the meta definition).

In `@web/src/pages/agents/AgentFilters.stories.tsx`:
- Around line 9-25: The decorator is mutating the global Zustand store during
render by calling useAgentsStore.setState(...) (and similarly in the other
decorator block), which causes repeated writes and state leakage; fix it by
moving the reset into a Storybook loader or a wrapper component that calls
useAgentsStore.setState(...) inside a useEffect (or run once in a loader) so the
store is reset only on mount rather than during render, keep the MemoryRouter
and Story rendering as-is, and apply the same change for the other decorator
that currently resets
departmentFilter/levelFilter/statusFilter/sortBy/searchQuery.

In `@web/src/pages/agents/AgentGridView.tsx`:
- Around line 35-50: The JSX inside agents.map in AgentGridView is too complex;
extract the mapped body into a new presentational component (e.g., AgentGridItem
or AgentCardLink) that accepts an agent prop (or individual fields) and returns
the StaggerItem -> Link -> AgentCard tree using encodeURIComponent(agent.name),
toRuntimeStatus(agent.status) and formatRelativeTime(agent.hiring_date); then
replace the inline JSX in AgentGridView with agents.map(a => <AgentGridItem
key={a.id} agent={a} />). Ensure the new component imports/uses StaggerItem,
Link, ROUTES, AgentCard, toRuntimeStatus and formatRelativeTime and preserves
the key on the top-level rendered element.

In `@web/src/pages/agents/AgentIdentityHeader.tsx`:
- Around line 39-41: Replace the plain <span> used for the hired date inside the
AgentIdentityHeader component with a semantic <time> element: keep the same
className and displayed text using formatDate(agent.hiring_date) but add a
datetime attribute set to the machine-readable ISO value of agent.hiring_date
(e.g., new Date(agent.hiring_date).toISOString() or ensure agent.hiring_date is
already ISO) so assistive tech and crawlers can parse the date; refer to
AgentIdentityHeader, formatDate, and agent.hiring_date to locate and update the
element.

In `@web/src/pages/agents/CareerTimelineEvent.tsx`:
- Around line 45-47: The timestamp is rendered in a non-semantic span; update
the CareerTimelineEvent component to use a semantic time element instead.
Replace the span that displays {formatDate(event.timestamp)} with a <time>
element that sets its dateTime attribute to event.timestamp (or a ISO string)
and keeps the same className ("text-micro font-mono text-muted-foreground") and
children as formatDate(event.timestamp) so screen readers and browsers can
understand the timestamp; ensure references to formatDate and event.timestamp
remain unchanged.

In `@web/src/pages/agents/ProseInsight.tsx`:
- Around line 21-25: The current list rendering uses the insight string as the
React key in the insights.map(...) block which can collide if duplicate insight
strings occur; change the key to a stable index-based key (e.g., use the map
index) in the <p> elements inside the insights.map callback to avoid
duplicate-key issues since these items are display-only and not reordered or
filtered.

In `@web/src/pages/agents/TaskHistoryBar.tsx`:
- Around line 19-37: getBarWidth and formatDuration reuse raw updated_at which
can be unparseable or earlier than created_at; compute a single effectiveEnd
timestamp (parse updated_at and if it's NaN or earlier than created_at use
created_at) and use that in both functions to avoid NaN and negative durations,
ensure you clamp durationMs to >= 0 before computing pct (in getBarWidth, use
maxDurationMs guard then compute pct with Math.max(20, Math.min(100, (durationMs
/ maxDurationMs) * 100))) and format seconds/minutes/hours from the non-negative
duration in formatDuration; refer to the functions getBarWidth, formatDuration
and the Task fields created_at and updated_at when making the change.

---

Duplicate comments:
In `@web/src/pages/agents/ActivityLog.tsx`:
- Around line 39-44: The list key currently uses a mutable index which causes
unnecessary remounts; update the map key in the StaggerItem within the
events.map to use a stable identifier from the event itself (e.g., event.id)
instead of `${...}-${index}`—if AgentActivityEvent does not yet expose id, add a
stable id property to AgentActivityEvent (or derive a deterministic key from
immutable fields like event_type and timestamp) and use that value as the key
for StaggerItem and ActivityLogItem so keys remain stable across live prepends.

In `@web/src/pages/agents/AgentFilters.stories.tsx`:
- Around line 6-27: The Storybook meta for AgentFilters is missing the required
accessibility test setting; update the meta object (the constant named meta) to
include a parameters property with a11y.test set to one of 'error' | 'todo' |
'off' (e.g., parameters: { a11y: { test: 'error' } }) so Storybook will
run/record a11y checks for the AgentFilters story; ensure this change sits
alongside the existing title/component/decorators entries in the meta object.

In `@web/src/pages/agents/AgentIdentityHeader.stories.tsx`:
- Around line 30-34: The Storybook meta for AgentIdentityHeader is missing the
required accessibility test setting; update the meta object (the constant named
"meta" for component AgentIdentityHeader) to include a parameters.a11y.test
property set to one of 'error' | 'todo' | 'off' (choose the appropriate value
for this story), preserving existing fields like title and decorators so
Storybook picks up the a11y rule.

In `@web/src/stores/agents.ts`:
- Around line 105-112: fetchAgentDetail currently overwrites the activity buffer
with the newest first page on every refresh, which causes rows appended by
fetchMoreActivity() to be lost; update fetchAgentDetail (the Promise.allSettled
block that assigns activity) so that when selectedAgent?.name === name you
merge/prepend the freshly fetched page 1 into the existing activity buffer
instead of replacing it and dedupe entries (by unique id/timestamp) to avoid
duplicates; apply the same merge behavior to the second occurrence noted (lines
~131-136) so both refresh paths preserve paginated items appended by
fetchMoreActivity().
- Around line 58-60: The current staleness guard _detailRequestName only changes
on route change and fails when multiple requests for the same agent overlap;
replace it with a monotonic request token: add a numeric _detailRequestId that
you increment each time fetchAgentDetail is invoked, capture the current id in
the local scope of the request, and before every state mutation (every set()
call and error path) compare the captured id to the latest _detailRequestId and
bail if they differ; update the logic inside fetchAgentDetail (and any related
handlers around the existing set() calls and error handling referenced in the
diff) to use this request-id check so older responses cannot overwrite newer
ones.
- Around line 87-95: fetchAgents currently only requests the first page (limit:
200) via listAgents, which causes client-side search/filter/sort over only that
page; update fetchAgents to exhaust pagination by repeatedly calling listAgents
with an offset/page token (or increasing page number) until you have fetched
result.total items and append each page's result.data to state.agents, then set
totalAgents and clear listLoading/listError, or alternatively move
filtering/sorting into listAgents so the server returns filtered results; target
the fetchAgents function and its use of listAgents/result.total/result.data when
implementing the change.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 9c2bdd7e-0dd0-4a90-84f6-e27c37e95666

📥 Commits

Reviewing files that changed from the base of the PR and between a222c73 and 9dbc51b.

📒 Files selected for processing (37)
  • CLAUDE.md
  • docs/design/page-structure.md
  • web/src/__tests__/stores/agents.test.ts
  • web/src/__tests__/utils/agents.property.test.ts
  • web/src/__tests__/utils/agents.test.ts
  • web/src/api/endpoints/agents.ts
  • web/src/api/types.ts
  • web/src/hooks/useAgentDetailData.ts
  • web/src/hooks/useAgentsData.ts
  • web/src/pages/AgentDetailPage.tsx
  • web/src/pages/AgentsPage.tsx
  • web/src/pages/agents/ActivityLog.stories.tsx
  • web/src/pages/agents/ActivityLog.tsx
  • web/src/pages/agents/ActivityLogItem.tsx
  • web/src/pages/agents/AgentDetailSkeleton.stories.tsx
  • web/src/pages/agents/AgentDetailSkeleton.tsx
  • web/src/pages/agents/AgentFilters.stories.tsx
  • web/src/pages/agents/AgentFilters.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/agents/AgentsSkeleton.tsx
  • web/src/pages/agents/CareerTimeline.stories.tsx
  • web/src/pages/agents/CareerTimeline.tsx
  • web/src/pages/agents/CareerTimelineEvent.tsx
  • web/src/pages/agents/PerformanceMetrics.stories.tsx
  • web/src/pages/agents/PerformanceMetrics.tsx
  • web/src/pages/agents/ProseInsight.stories.tsx
  • web/src/pages/agents/ProseInsight.tsx
  • web/src/pages/agents/TaskHistory.stories.tsx
  • web/src/pages/agents/TaskHistory.tsx
  • web/src/pages/agents/TaskHistoryBar.tsx
  • web/src/pages/agents/ToolBadges.stories.tsx
  • web/src/pages/agents/ToolBadges.tsx
  • web/src/stores/agents.ts
  • web/src/utils/agents.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (4)
**/*.md

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • CLAUDE.md
  • docs/design/page-structure.md
web/src/**/*.{tsx,ts}

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • web/src/pages/agents/AgentDetailSkeleton.tsx
  • web/src/pages/agents/AgentDetailSkeleton.stories.tsx
  • web/src/pages/agents/CareerTimeline.tsx
  • web/src/pages/agents/ActivityLogItem.tsx
  • web/src/pages/agents/CareerTimelineEvent.tsx
  • web/src/pages/agents/ProseInsight.tsx
  • web/src/pages/agents/AgentsSkeleton.tsx
  • web/src/pages/AgentsPage.tsx
  • web/src/pages/agents/AgentGridView.tsx
  • web/src/api/endpoints/agents.ts
  • web/src/pages/agents/AgentIdentityHeader.stories.tsx
  • web/src/pages/agents/ToolBadges.tsx
  • web/src/pages/agents/ToolBadges.stories.tsx
  • web/src/pages/agents/PerformanceMetrics.stories.tsx
  • web/src/pages/agents/AgentFilters.tsx
  • web/src/pages/AgentDetailPage.tsx
  • web/src/pages/agents/PerformanceMetrics.tsx
  • web/src/api/types.ts
  • web/src/pages/agents/ProseInsight.stories.tsx
  • web/src/pages/agents/ActivityLog.stories.tsx
  • web/src/pages/agents/AgentIdentityHeader.tsx
  • web/src/pages/agents/TaskHistoryBar.tsx
  • web/src/pages/agents/ActivityLog.tsx
  • web/src/__tests__/utils/agents.property.test.ts
  • web/src/pages/agents/AgentGridView.stories.tsx
  • web/src/pages/agents/TaskHistory.tsx
  • web/src/pages/agents/CareerTimeline.stories.tsx
  • web/src/hooks/useAgentsData.ts
  • web/src/pages/agents/TaskHistory.stories.tsx
  • web/src/__tests__/stores/agents.test.ts
  • web/src/pages/agents/AgentFilters.stories.tsx
  • web/src/hooks/useAgentDetailData.ts
  • web/src/__tests__/utils/agents.test.ts
  • web/src/utils/agents.ts
  • web/src/stores/agents.ts
web/src/**/*.stories.tsx

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • web/src/pages/agents/AgentDetailSkeleton.stories.tsx
  • web/src/pages/agents/AgentIdentityHeader.stories.tsx
  • web/src/pages/agents/ToolBadges.stories.tsx
  • web/src/pages/agents/PerformanceMetrics.stories.tsx
  • web/src/pages/agents/ProseInsight.stories.tsx
  • web/src/pages/agents/ActivityLog.stories.tsx
  • web/src/pages/agents/AgentGridView.stories.tsx
  • web/src/pages/agents/CareerTimeline.stories.tsx
  • web/src/pages/agents/TaskHistory.stories.tsx
  • web/src/pages/agents/AgentFilters.stories.tsx
docs/design/**/*.md

📄 CodeRabbit inference engine (CLAUDE.md)

Always read the relevant docs/design/ page before implementing any feature or planning any issue; DESIGN_SPEC.md is a pointer file to 11 design pages

Files:

  • docs/design/page-structure.md
🧠 Learnings (27)
📓 Common learnings
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T12:41:55.315Z
Learning: After PR exists, use `/aurelio-review-pr` to handle external reviewer feedback; fix all valid issues found (including pre-existing issues in surrounding code and adjacent suggestions) -- never skip or defer
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-16T06:24:56.341Z
Learning: Applies to docs/design/**/*.md : Design specification pages in `docs/design/` must be consulted before implementing features (7 pages: index, agents, organization, communication, engine, memory, operations)
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to docs/design/*.md : Design spec pages: 7 pages in `docs/design/` — index, agents, organization, communication, engine, memory, operations
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to src/synthorg/**/*.py : Package structure: src/synthorg/ organized as: api/ (REST+WebSocket, Litestar), auth/ (auth subpackage), backup/ (scheduled/manual backups), budget/ (cost tracking, CFO), cli/ (superseded by Go CLI), communication/ (message bus, meetings), config/ (YAML loading), core/ (domain models, resilience config), engine/ (orchestration, task state, coordination, approval gates, stagnation detection, context budget, compaction), hr/ (hiring, performance, promotion), memory/ (pluggable backend, Mem0, retrieval, consolidation), persistence/ (operational data, SQLite, settings), observability/ (logging, correlation, sinks), providers/ (LLM abstraction, LiteLLM, auth types, presets, runtime CRUD), settings/ (runtime-editable, typed definitions, encryption, config bridge), security/ (SecOps, rule engine, output scanning, progressive trust, autonomy levels), templates/ (company templates, personalities), tools/ (registry, built-in tools, git, sandbox, code_runner, MCP...

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-03-15T21:20:09.993Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:20:09.993Z
Learning: Applies to web/src/components/** : Vue components organized by feature (agents/, approvals/, budget/, common/, dashboard/, layout/, messages/, org-chart/, tasks/).

Applied to files:

  • CLAUDE.md
  • web/src/pages/AgentsPage.tsx
  • web/src/pages/agents/AgentFilters.tsx
  • docs/design/page-structure.md
📚 Learning: 2026-03-15T18:17:43.675Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Applies to web/** : Web dashboard: Node.js 20+, dependencies in web/package.json (Vue 3, PrimeVue, Tailwind CSS, Pinia, VueFlow, ECharts, Axios, vue-draggable-plus, Vitest, fast-check, ESLint, vue-tsc).

Applied to files:

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

Applied to files:

  • CLAUDE.md
  • web/src/pages/agents/AgentDetailSkeleton.stories.tsx
  • web/src/pages/agents/CareerTimelineEvent.tsx
  • web/src/pages/agents/ProseInsight.tsx
  • web/src/pages/agents/AgentIdentityHeader.stories.tsx
  • web/src/pages/agents/ToolBadges.tsx
  • web/src/pages/agents/ToolBadges.stories.tsx
  • web/src/pages/agents/PerformanceMetrics.stories.tsx
  • web/src/pages/agents/ProseInsight.stories.tsx
  • web/src/pages/agents/ActivityLog.stories.tsx
  • web/src/pages/agents/AgentGridView.stories.tsx
  • web/src/pages/agents/CareerTimeline.stories.tsx
  • web/src/pages/agents/TaskHistory.stories.tsx
  • web/src/pages/agents/AgentFilters.stories.tsx
📚 Learning: 2026-03-14T15:43:05.601Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-14T15:43:05.601Z
Learning: Applies to web/package.json : Web dashboard Node.js 20+; dependencies in web/package.json (Vue 3, PrimeVue, Tailwind CSS, Pinia, VueFlow, ECharts, Axios, vue-draggable-plus, Vitest, ESLint, vue-tsc)

Applied to files:

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

Applied to files:

  • CLAUDE.md
  • web/src/pages/agents/AgentDetailSkeleton.tsx
  • web/src/pages/agents/CareerTimeline.tsx
  • web/src/pages/agents/CareerTimelineEvent.tsx
  • web/src/pages/agents/AgentsSkeleton.tsx
  • web/src/pages/AgentsPage.tsx
  • web/src/pages/agents/AgentGridView.tsx
  • web/src/pages/agents/ToolBadges.tsx
  • web/src/pages/agents/ToolBadges.stories.tsx
  • web/src/pages/AgentDetailPage.tsx
  • web/src/pages/agents/PerformanceMetrics.tsx
  • web/src/pages/agents/AgentIdentityHeader.tsx
  • web/src/pages/agents/TaskHistoryBar.tsx
  • web/src/pages/agents/ActivityLog.tsx
  • docs/design/page-structure.md
  • web/src/pages/agents/TaskHistory.tsx
  • web/src/utils/agents.ts
📚 Learning: 2026-03-27T12:41:55.315Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T12:41:55.315Z
Learning: Applies to web/src/**/*.{tsx,ts} : Always reuse existing components from `web/src/components/ui/` before creating new ones. Check the required component inventory (StatusBadge, MetricCard, Sparkline, SectionCard, AgentCard, DeptHealthBar, ProgressGauge, StatPill, Avatar, Button, Toast, Skeleton, EmptyState, ErrorBoundary, ConfirmDialog, CommandPalette, InlineEdit, AnimatedPresence, StaggerGroup, TaskStatusIndicator, PriorityBadge)

Applied to files:

  • CLAUDE.md
  • web/src/pages/agents/AgentDetailSkeleton.tsx
  • web/src/pages/agents/CareerTimelineEvent.tsx
  • web/src/pages/agents/AgentsSkeleton.tsx
  • web/src/pages/AgentsPage.tsx
  • web/src/pages/agents/AgentGridView.tsx
  • web/src/pages/agents/ToolBadges.tsx
  • web/src/pages/agents/ToolBadges.stories.tsx
  • web/src/pages/agents/AgentFilters.tsx
  • web/src/pages/AgentDetailPage.tsx
  • web/src/pages/agents/PerformanceMetrics.tsx
  • web/src/pages/agents/AgentIdentityHeader.tsx
  • web/src/pages/agents/TaskHistoryBar.tsx
  • web/src/pages/agents/ActivityLog.tsx
  • docs/design/page-structure.md
  • web/src/pages/agents/TaskHistory.tsx
  • web/src/utils/agents.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:

  • CLAUDE.md
  • web/src/__tests__/utils/agents.property.test.ts
  • web/src/__tests__/stores/agents.test.ts
  • web/src/__tests__/utils/agents.test.ts
📚 Learning: 2026-03-14T15:43:05.601Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-14T15:43:05.601Z
Learning: Applies to docs/** : Docs source in docs/ (Markdown, built with Zensical); design spec in docs/design/ (7 pages: index, agents, organization, communication, engine, memory, operations)

Applied to files:

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

Applied to files:

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

Applied to files:

  • web/src/pages/agents/AgentDetailSkeleton.stories.tsx
  • web/src/pages/agents/AgentIdentityHeader.stories.tsx
  • web/src/pages/agents/ToolBadges.stories.tsx
  • web/src/pages/agents/PerformanceMetrics.stories.tsx
  • web/src/pages/agents/ProseInsight.stories.tsx
  • web/src/pages/agents/ActivityLog.stories.tsx
  • web/src/pages/agents/AgentGridView.stories.tsx
  • web/src/pages/agents/CareerTimeline.stories.tsx
  • web/src/pages/agents/TaskHistory.stories.tsx
  • web/src/__tests__/stores/agents.test.ts
  • web/src/pages/agents/AgentFilters.stories.tsx
📚 Learning: 2026-03-27T12:41:55.315Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T12:41:55.315Z
Learning: Applies to web/src/**/*.{tsx,ts} : Use density-aware spacing tokens (`p-card`, `gap-section-gap`, `gap-grid-gap`) or standard Tailwind spacing; never hardcode pixel values for layout spacing

Applied to files:

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

Applied to files:

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

Applied to files:

  • web/src/pages/agents/CareerTimelineEvent.tsx
📚 Learning: 2026-03-15T21:49:53.264Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:49:53.264Z
Learning: Fix everything valid — never skip when review agents find valid issues (including pre-existing issues in surrounding code, suggestions, and findings adjacent to the PR's changes). No deferring, no 'out of scope' skipping.

Applied to files:

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

Applied to files:

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

Applied to files:

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

Applied to files:

  • web/src/api/types.ts
📚 Learning: 2026-03-16T06:24:56.341Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-16T06:24:56.341Z
Learning: Applies to docs/design/**/*.md : Design specification pages in `docs/design/` must be consulted before implementing features (7 pages: index, agents, organization, communication, engine, memory, operations)

Applied to files:

  • docs/design/page-structure.md
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to docs/design/*.md : Design spec pages: 7 pages in `docs/design/` — index, agents, organization, communication, engine, memory, operations

Applied to files:

  • docs/design/page-structure.md
📚 Learning: 2026-03-19T07:13:44.964Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:13:44.964Z
Learning: Always read the relevant `docs/design/` page before implementing any feature or planning any issue — DESIGN_SPEC.md is a pointer file linking to 7 design pages (Agents, Organization, Communication, Engine, Memory, Operations)

Applied to files:

  • docs/design/page-structure.md
📚 Learning: 2026-03-15T18:38:44.202Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:38:44.202Z
Learning: Always read the relevant `docs/design/` page before implementing any feature or planning any issue. DESIGN_SPEC.md is a pointer file linking to the 7 design pages (index, agents, organization, communication, engine, memory, operations).

Applied to files:

  • docs/design/page-structure.md
📚 Learning: 2026-03-27T12:41:55.315Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T12:41:55.315Z
Learning: When approved deviations from design spec occur, update the relevant `docs/design/` page to reflect the new reality

Applied to files:

  • docs/design/page-structure.md
📚 Learning: 2026-03-18T08:23:08.912Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-18T08:23:08.912Z
Learning: When approved deviations occur, update the relevant `docs/design/` page to reflect the new reality.

Applied to files:

  • docs/design/page-structure.md
📚 Learning: 2026-03-27T12:41:55.315Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T12:41:55.315Z
Learning: Applies to docs/design/**/*.md : Always read the relevant `docs/design/` page before implementing any feature or planning any issue; DESIGN_SPEC.md is a pointer file to 11 design pages

Applied to files:

  • docs/design/page-structure.md
📚 Learning: 2026-03-17T22:08:13.456Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T22:08:13.456Z
Learning: Engine: Agent orchestration, execution loops, parallel execution, task decomposition, routing, task assignment, centralized single-writer task state engine (TaskEngine), task lifecycle, recovery, shutdown, workspace isolation, coordination (multi-agent pipeline: TopologyDispatcher protocol, 4 dispatchers — SAS/centralized/decentralized/context-dependent, wave execution, workspace lifecycle integration, CoordinationSectionConfig company config bridge, build_coordinator factory), coordination error classification, prompt policy validation, checkpoint recovery (checkpoint/, per-turn persistence, heartbeat detection, CheckpointRecoveryStrategy), approval gate (escalation detection, context parking/resume, EscalationInfo/ResumePayload models), stagnation detection (stagnation/, StagnationDetector protocol, ToolRepetitionDetector, dual-signal analysis, corrective prompt injection), agent runtime state (AgentRuntimeState, lightweight per-agent execution status for dashboard queries and recove...

Applied to files:

  • docs/design/page-structure.md
🪛 GitHub Check: Dashboard Lint
web/src/pages/agents/CareerTimeline.tsx

[warning] 25-25:
Do not use item index in the array as its key

web/src/pages/agents/ToolBadges.tsx

[warning] 32-32:
Do not use item index in the array as its key

web/src/pages/agents/ActivityLog.tsx

[warning] 41-41:
Do not use item index in the array as its key

🔇 Additional comments (23)
CLAUDE.md (1)

127-131: LGTM!

Documentation updates accurately reflect the new page data composition hooks and per-domain stores introduced for the Agents feature.

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

1-15: LGTM!

Clean skeleton implementation that properly reuses Skeleton and SkeletonCard from the UI inventory. Responsive grid breakpoints and density-aware spacing tokens (gap-grid-gap) follow design system conventions.

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

1-45: LGTM!

Excellent skeleton structure that mirrors the agent detail page layout. Proper reuse of Skeleton, SkeletonCard, and SkeletonMetric components from the UI inventory. Responsive breakpoints and spacing tokens follow design system conventions.

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

1-13: LGTM!

Standard Storybook 10 story configuration. The Default story adequately covers the skeleton's single visual state.

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

1-29: LGTM!

Comprehensive story coverage with SingleInsight, MultipleInsights, and Empty variants that exercise all rendering paths of the component.

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

1-37: LGTM!

Well-structured component that properly reuses SectionCard and extracts ToolBadge as a helper component per coding guidelines. The composite key ${tool}-${index} is appropriate here—the static analysis warning is a false positive since tools won't be dynamically reordered.

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

1-23: LGTM!

Good story coverage with Default, SingleTool, and Empty variants that exercise all rendering paths including the null return case.

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

13-24: Looks good — semantic timestamp and safe icon rendering are implemented correctly.

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

30-50: Accessibility handling for runtime banners is correctly implemented (alert/status live regions).

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

17-27: Good composition — this cleanly reuses SectionCard + MetricCard and handles empty states safely.

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

15-33: LGTM — timeline section handles both empty and populated states clearly and consistently.

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

1-1: No changes needed; the current import is correct for Storybook 10.

The story correctly imports Meta and StoryObj from @storybook/react (the renderer package). For Storybook 10, type imports come from the renderer package (@storybook/react), while definePreview configuration comes from the framework package (@storybook/react-vite). The current code is correct.

			> Likely an incorrect or invalid review comment.
web/src/pages/agents/CareerTimeline.stories.tsx (1)

1-62: LGTM!

Well-structured Storybook stories with deterministic timestamps via FIXED_BASE and a clean makeEvent helper. The story variants (Default, Empty, LongCareer, Fired) provide good coverage of the CareerTimeline component states.

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

1-48: LGTM!

Clean implementation that properly reuses UI components (SectionCard, EmptyState, StaggerGroup) from the shared inventory. The date validation and fallback logic correctly handles edge cases with invalid updated_at timestamps while filtering tasks with invalid created_at.

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

1-52: LGTM!

Comprehensive makeTask helper with proper defaults for all Task fields, and deterministic timestamps for reproducible story rendering. Good coverage with Default, Empty, and SingleTask variants.

web/src/api/types.ts (2)

46-52: LGTM!

The runtime value arrays (SENIORITY_LEVEL_VALUES, AGENT_STATUS_VALUES) using as const satisfies readonly X[] provide both type safety and runtime access for filter validation and test arbitraries.


383-452: LGTM!

Well-structured performance and career types with:

  • Proper readonly annotations on array fields (windows, trends, related_ids, metadata)
  • Documented invariant for WindowMetrics (tasks_completed + tasks_failed === data_point_count)
  • Consistent pattern with existing type definitions
docs/design/page-structure.md (2)

67-82: LGTM!

The Agent Detail specification is now consistent throughout the document, correctly describing it as a full-page route at /agents/{agentName} with clearly defined sections (Identity, Prose, Performance, Tools, Career, Task history, Activity log) and appropriate API endpoints.


253-254: LGTM!

WebSocket subscription guidance correctly differentiates between list view (subscribes to agents only) and detail view (subscribes to both agents and tasks), enabling task-related updates to trigger detail page refreshes.

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

44-50: ESLint disable comment is reasonable.

The comment correctly explains that polling returns a new object each render while start/stop are stable, so including it would restart polling unnecessarily. This is an acceptable deviation from exhaustive-deps.

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

1-90: LGTM!

Well-structured stories with MemoryRouter wrapper for routing context, comprehensive makeAgent helper, and good coverage including edge cases (Empty, SingleAgent) and stress testing (ManyAgents with 12 items).

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

81-119: LGTM!

The arbitraries correctly enforce documented invariants:

  • arbWindowMetrics uses fc.chain to ensure tasks_completed + tasks_failed === data_point_count
  • arbPerformance generates tasks_completed_total first and constrains 7d/30d values to not exceed it

267-278: LGTM!

The formatCostPerTask property test is now currency-agnostic, correctly checking for digits and a currency symbol without assuming a specific currency (USD/EUR), which aligns with the API contract where the value is named cost_per_task_usd but the formatter may use locale-specific symbols.

Comment on lines +91 to +105
const bindings: ChannelBinding[] = useMemo(
() =>
agentName
? DETAIL_CHANNELS.map((channel) => ({
channel,
handler: () => {
useAgentsStore.getState().fetchAgentDetail(agentName)
},
}))
: EMPTY_BINDINGS,
[agentName],
)

const { connected: wsConnected, setupError: wsSetupError } = useWebSocket({ bindings })

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

Filter WebSocket refreshes to the current agent.

Every event on the global agents or tasks channels triggers fetchAgentDetail(agentName) here. Since fetchAgentDetail() on Lines 105-111 in web/src/stores/agents.ts fans out into five REST calls, unrelated events can cause noisy reloads and unnecessary backend load for an open profile. Pass an agent-specific filters option to useWebSocket, or ignore events whose payload is for another agent before refetching.

🤖 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 91 - 105, The current
WebSocket bindings in useAgentDetailData.ts call fetchAgentDetail(agentName) on
every global agents/tasks event, causing noisy reloads; update the
ChannelBinding creation (where DETAIL_CHANNELS is mapped and useWebSocket is
called) to either pass an agent-specific filters option into useWebSocket (so
only events for the current agent are delivered) or keep bindings unchanged but
change each handler to inspect the event payload and return early if the
payload.agentName (or id) does not match the local agentName before calling
fetchAgentDetail; ensure you reference the existing DETAIL_CHANNELS mapping and
the fetchAgentDetail call so the check/filter is applied only for the current
agent.

Comment on lines +53 to +63
const bindings: ChannelBinding[] = useMemo(
() =>
AGENT_CHANNELS.map((channel) => ({
channel,
handler: () => {
// Refresh agent list on any agent event
useAgentsStore.getState().fetchAgents()
},
})),
[],
)
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 debouncing WebSocket-triggered refreshes.

The current implementation calls fetchAgents() on every agent WebSocket event. If multiple agent events arrive in quick succession (e.g., bulk status changes), this could trigger redundant API calls.

♻️ Optional: Debounce the refresh
+import { useDebouncedCallback } from 'use-debounce'
+
+const WS_DEBOUNCE_MS = 500
+
 // WebSocket
+const debouncedFetch = useDebouncedCallback(() => {
+  useAgentsStore.getState().fetchAgents()
+}, WS_DEBOUNCE_MS)
+
 const bindings: ChannelBinding[] = useMemo(
   () =>
     AGENT_CHANNELS.map((channel) => ({
       channel,
       handler: () => {
-        // Refresh agent list on any agent event
-        useAgentsStore.getState().fetchAgents()
+        debouncedFetch()
       },
     })),
-  [],
+  [debouncedFetch],
 )
🤖 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 53 - 63, The current bindings
call useAgentsStore.getState().fetchAgents() for every AGENT_CHANNELS event
causing redundant API calls; wrap that handler with a debounced refresher (e.g.,
createDebouncedFetch or use a lodash debounce) so rapid events trigger a single
fetch. Update the binding handler in the bindings array (the object with channel
and handler) to call the debounced function instead of fetchAgents directly,
ensure the debounced function is created once (useRef or module-level singleton)
and cleaned up if needed to avoid leaks.

Comment on lines +17 to +33
const {
agent,
performanceCards,
insights,
agentTasks,
activity,
activityTotal,
careerHistory,
loading,
error,
wsConnected,
wsSetupError,
fetchMoreActivity,
} = useAgentDetailData(agentName ?? '')

if (loading && !agent) {
return <AgentDetailSkeleton />
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

Prevent stale agent details from flashing during route changes.

useAgentDetailData starts refetching in an effect, so when :agentName changes this page can render the previous selectedAgent for one commit because the guard only checks !agent. Please gate rendering on the current route param as well, or clear detail before the next route commit, so /agents/Bob never paints Alice's profile.

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

In `@web/src/pages/AgentDetailPage.tsx` around lines 17 - 33, The page can briefly
render the previous agent while refetching; update the render guard in
AgentDetailPage to also verify that the loaded agent matches the current route
param (agentName) or ensure useAgentDetailData clears the detail when agentName
changes: specifically, modify the existing guard that returns
AgentDetailSkeleton (currently testing loading && !agent) to also check
agent?.name (or the equivalent selectedAgent id) against agentName, or add logic
in useAgentDetailData to reset selectedAgent to null when agentName changes so
/agents/Bob never paints Alice's profile.

- Add staleness guard tests: verify stale response rejection on rapid
  navigation and after clearDetail
- Fix arbPerformance invariant: tasks_completed_7d <= tasks_completed_30d
- Extract AgentGridItem from 14-line .map() block (>8 line threshold)
- Use semantic <time> for hired date and career event timestamps
- Use index key for ProseInsight (string keys can collide)
- Add effectiveEndMs helper in TaskHistoryBar to guard against NaN from
  unparseable updated_at (parent fix didn't cover child component)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@Aureliolo Aureliolo temporarily deployed to cloudflare-preview March 27, 2026 13:24 — with GitHub Actions Inactive
@Aureliolo
Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 27, 2026

✅ Actions performed

Review triggered.

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

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@web/src/__tests__/stores/agents.test.ts`:
- Around line 357-378: The test for clearDetail is missing assertions for
agentTasks, activity, and careerHistory so regressions can slip by; update the
test that calls useAgentsStore.getState().clearDetail() to also assert that
state.agentTasks, state.activity, and state.careerHistory are reset to empty
arrays (or their intended empty state) in addition to the existing assertions on
selectedAgent, performance, activityTotal, detailLoading, and detailError,
referencing useAgentsStore and the clearDetail method.
- Around line 289-303: The timestamps in the activity fixtures (variables
existingEvents and newEvents used when calling useAgentsStore.setState and
mocking getAgentActivity) can produce invalid hours >23; update the timestamp
generation to ensure the hour component is within 00–23 (e.g., use i % 24 or
compute a date and add i hours) for both existingEvents and newEvents so the
produced ISO timestamps are always valid.

In `@web/src/pages/agents/TaskHistoryBar.tsx`:
- Around line 10-17: Change the TYPE_COLORS declaration to use the TaskType
union for stronger typing (i.e., make it Record<TaskType, string>) and ensure
the object includes an entry for every TaskType value so the compiler enforces
coverage; update the mapping keys in TYPE_COLORS to the exact TaskType names and
remove the runtime fallback (the "?? 'bg-accent'" usage) where colors are read
since the type now guarantees a mapping exists.
- Around line 19-26: The maxDurationMs computation in TaskHistory.tsx must use
the same clamping as effectiveEndMs: when computing the task end time, parse
updated_at and if it is NaN or earlier than created_at, fall back to created_at
instead of using the raw updated_at (which can create negative durations);
update the logic that computes the end timestamp for duration/maxDurationMs to
mirror effectiveEndMs so both components treat updated_at < created_at as
created_at.
- Around line 19-26: The effectiveEndMs function parses task.created_at without
validating it, which can yield NaN and break downstream percent math; update
effectiveEndMs (and related helpers getBarWidth/formatDuration if they reparse)
to validate the result of new Date(task.created_at).getTime() and treat an
unparseable created_at as missing — e.g., if createdMs is NaN, fall back to
using updated_at parse or a safe default (or return 0) and ensure updated_at is
also validated before use; reference function effectiveEndMs (and callers
getBarWidth/formatDuration) to locate where to add the NaN checks and fallbacks.
🪄 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: 626be665-2263-42c6-8c71-874b133f66a0

📥 Commits

Reviewing files that changed from the base of the PR and between 9dbc51b and 366802d.

📒 Files selected for processing (7)
  • web/src/__tests__/stores/agents.test.ts
  • web/src/__tests__/utils/agents.property.test.ts
  • web/src/pages/agents/AgentGridView.tsx
  • web/src/pages/agents/AgentIdentityHeader.tsx
  • web/src/pages/agents/CareerTimelineEvent.tsx
  • web/src/pages/agents/ProseInsight.tsx
  • web/src/pages/agents/TaskHistoryBar.tsx
📜 Review details
🧰 Additional context used
📓 Path-based instructions (1)
web/src/**/*.{tsx,ts}

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • web/src/pages/agents/CareerTimelineEvent.tsx
  • web/src/pages/agents/ProseInsight.tsx
  • web/src/pages/agents/AgentIdentityHeader.tsx
  • web/src/__tests__/utils/agents.property.test.ts
  • web/src/pages/agents/AgentGridView.tsx
  • web/src/pages/agents/TaskHistoryBar.tsx
  • web/src/__tests__/stores/agents.test.ts
🧠 Learnings (10)
📓 Common learnings
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T22:08:13.456Z
Learning: Engine: Agent orchestration, execution loops, parallel execution, task decomposition, routing, task assignment, centralized single-writer task state engine (TaskEngine), task lifecycle, recovery, shutdown, workspace isolation, coordination (multi-agent pipeline: TopologyDispatcher protocol, 4 dispatchers — SAS/centralized/decentralized/context-dependent, wave execution, workspace lifecycle integration, CoordinationSectionConfig company config bridge, build_coordinator factory), coordination error classification, prompt policy validation, checkpoint recovery (checkpoint/, per-turn persistence, heartbeat detection, CheckpointRecoveryStrategy), approval gate (escalation detection, context parking/resume, EscalationInfo/ResumePayload models), stagnation detection (stagnation/, StagnationDetector protocol, ToolRepetitionDetector, dual-signal analysis, corrective prompt injection), agent runtime state (AgentRuntimeState, lightweight per-agent execution status for dashboard queries and recove...
📚 Learning: 2026-03-27T12:41:55.315Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T12:41:55.315Z
Learning: Applies to web/src/**/*.{tsx,ts} : Use density-aware spacing tokens (`p-card`, `gap-section-gap`, `gap-grid-gap`) or standard Tailwind spacing; never hardcode pixel values for layout spacing

Applied to files:

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

Applied to files:

  • web/src/pages/agents/CareerTimelineEvent.tsx
  • web/src/pages/agents/ProseInsight.tsx
  • web/src/pages/agents/AgentIdentityHeader.tsx
  • web/src/pages/agents/AgentGridView.tsx
  • web/src/pages/agents/TaskHistoryBar.tsx
📚 Learning: 2026-03-27T12:41:55.315Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T12:41:55.315Z
Learning: Applies to web/src/**/*.{tsx,ts} : Use token variables for shadows and borders (`var(--so-shadow-card-hover)`, `border-border`, `border-bright`)

Applied to files:

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

Applied to files:

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

Applied to files:

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

Applied to files:

  • web/src/pages/agents/CareerTimelineEvent.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__/utils/agents.property.test.ts
  • web/src/__tests__/stores/agents.test.ts
📚 Learning: 2026-03-15T21:20:09.993Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:20:09.993Z
Learning: Applies to web/src/components/** : Vue components organized by feature (agents/, approvals/, budget/, common/, dashboard/, layout/, messages/, org-chart/, tasks/).

Applied to files:

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

Applied to files:

  • web/src/__tests__/stores/agents.test.ts
🪛 GitHub Check: Dashboard Lint
web/src/pages/agents/ProseInsight.tsx

[warning] 22-22:
Do not use item index in the array as its key

🔇 Additional comments (10)
web/src/pages/agents/ProseInsight.tsx (1)

9-27: Looks good — clean, safe, and guideline-aligned implementation.

Line 10’s empty-state guard is correct, and Lines 13-27 use semantic token-based classes with simple list rendering. The index key usage on Line 22 is acceptable for this static, display-only prose list and avoids prior string-collision risk.

Based on learnings: “Do NOT create complex (>8 line) JSX inside .map() — extract to shared component.”

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

81-121: Arbitrary generation now preserves key domain invariants.

Nice improvement on correlated counters in arbWindowMetrics/arbPerformance; this keeps properties realistic and reduces false negatives from impossible payloads.


269-277: Currency assertion is now contract-safe.

The regex-based check avoids hardcoding a symbol while still validating formatted currency output. Good fix for unit/currency neutrality.

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

45-50: Good semantic timestamp rendering.

Using <time dateTime={event.timestamp}> here is the right accessibility/semantics choice and keeps the display formatting decoupled from machine-readable time.

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

18-45: Excellent composition with shared UI primitives.

This cleanly follows the design-system rules (Avatar, StatusBadge, StatPill) and keeps the header implementation consistent with project conventions.

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

17-34: Nice extraction of grid item rendering.

Moving card/link JSX into AgentGridItem keeps the map concise and aligns with the complexity guideline while preserving behavior.

Also applies to: 54-56

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

210-263: Strong regression coverage for stale in-flight detail requests.

This section correctly exercises both out-of-order responses and post-clearDetail() invalidation, which is the core race-risk path in the detail store.

web/src/pages/agents/TaskHistoryBar.tsx (3)

1-8: LGTM!

Imports and props interface are clean and appropriately typed.


28-45: LGTM!

Helper functions correctly clamp durations to non-negative values and constrain bar widths to the [20, 100] range. The formatting logic handles seconds, minutes, and hours appropriately.


47-77: LGTM!

Component is well-structured with appropriate use of semantic color classes, typography tokens (font-sans, font-mono), and conditional styling via cn(). The extracted component pattern aligns with the coding guideline to avoid complex JSX in .map() calls.

Comment on lines +19 to +26
/** Parse updated_at safely; fall back to created_at if unparseable or earlier. */
function effectiveEndMs(task: Task): number {
const createdMs = new Date(task.created_at!).getTime()
if (!task.updated_at) return createdMs
const updatedMs = new Date(task.updated_at).getTime()
if (Number.isNaN(updatedMs) || updatedMs < createdMs) return createdMs
return updatedMs
}
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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify the maxDurationMs computation logic in TaskHistory.tsx
rg -n -A 10 'maxDurationMs' web/src/pages/agents/TaskHistory.tsx

Repository: Aureliolo/synthorg

Length of output: 789


Align updated_at clamping logic between TaskHistory.tsx and TaskHistoryBar.tsx.

TaskHistory.tsx computes maxDurationMs by using updated_at as-is when parseable, even if earlier than created_at, resulting in negative durations. However, effectiveEndMs in this file clamps to created_at when updated_at < created_at, computing 0 duration instead.

For a task with updated_at earlier than created_at, this inconsistency causes:

  • TaskHistory.tsx: negative raw duration contribution to maxDurationMs
  • TaskHistoryBar.tsx: 0 duration from clamped effectiveEndMs

This mismatch skews bar proportions. Align the clamping logic in TaskHistory.tsx line 24 to match effectiveEndMs: fall back to created_at when updated_at < created_at, not just when unparseable.

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

In `@web/src/pages/agents/TaskHistoryBar.tsx` around lines 19 - 26, The
maxDurationMs computation in TaskHistory.tsx must use the same clamping as
effectiveEndMs: when computing the task end time, parse updated_at and if it is
NaN or earlier than created_at, fall back to created_at instead of using the raw
updated_at (which can create negative durations); update the logic that computes
the end timestamp for duration/maxDurationMs to mirror effectiveEndMs so both
components treat updated_at < created_at as created_at.

⚠️ Potential issue | 🟡 Minor

Guard against unparseable created_at strings.

Line 21 parses created_at without validating the result. If created_at is a truthy but malformed string (e.g., "invalid"), createdMs becomes NaN, which propagates through calculations and results in width: NaN% in the rendered style.

The !task.created_at checks in getBarWidth and formatDuration catch undefined/null/empty, but not invalid date strings.

🛡️ Proposed fix
 function effectiveEndMs(task: Task): number {
   const createdMs = new Date(task.created_at!).getTime()
+  if (Number.isNaN(createdMs)) return Number.NaN // caller handles via existing guards or add explicit NaN check
   if (!task.updated_at) return createdMs
   const updatedMs = new Date(task.updated_at).getTime()
   if (Number.isNaN(updatedMs) || updatedMs < createdMs) return createdMs
   return updatedMs
 }

 function getBarWidth(task: Task, maxDurationMs: number): number {
-  if (!task.created_at || maxDurationMs <= 0) return 20
+  const createdMs = task.created_at ? new Date(task.created_at).getTime() : Number.NaN
+  if (!task.created_at || Number.isNaN(createdMs) || maxDurationMs <= 0) return 20

Alternatively, validate created_at parseability once and reuse:

 function getBarWidth(task: Task, maxDurationMs: number): number {
-  if (!task.created_at || maxDurationMs <= 0) return 20
+  if (!task.created_at || maxDurationMs <= 0) return 20
+  const startMs = new Date(task.created_at).getTime()
+  if (Number.isNaN(startMs)) return 20
-  const durationMs = Math.max(0, effectiveEndMs(task) - new Date(task.created_at).getTime())
+  const durationMs = Math.max(0, effectiveEndMs(task) - startMs)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/pages/agents/TaskHistoryBar.tsx` around lines 19 - 26, The
effectiveEndMs function parses task.created_at without validating it, which can
yield NaN and break downstream percent math; update effectiveEndMs (and related
helpers getBarWidth/formatDuration if they reparse) to validate the result of
new Date(task.created_at).getTime() and treat an unparseable created_at as
missing — e.g., if createdMs is NaN, fall back to using updated_at parse or a
safe default (or return 0) and ensure updated_at is also validated before use;
reference function effectiveEndMs (and callers getBarWidth/formatDuration) to
locate where to add the NaN checks and fallbacks.

- Strengthen clearDetail test: set non-empty agentTasks/activity/careerHistory
  before clearing, assert all fields reset
- Fix invalid ISO timestamps in activity fixtures (hours 24-98 are invalid)
- Use Record<TaskType, string> for TYPE_COLORS with compile-time coverage
- Align TaskHistory.tsx maxDurationMs with effectiveEndMs (handle updated_at
  earlier than created_at)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@Aureliolo Aureliolo temporarily deployed to cloudflare-preview March 27, 2026 13:41 — 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

♻️ Duplicate comments (1)
web/src/pages/agents/TaskHistoryBar.tsx (1)

19-26: ⚠️ Potential issue | 🟡 Minor

Guard against malformed created_at strings producing NaN.

The effectiveEndMs function assumes task.created_at is parseable when present. If created_at is a truthy but malformed string (e.g., "invalid"), createdMs becomes NaN, which propagates through all calculations and results in width: NaN% in the rendered style.

While getBarWidth and formatDuration guard against !task.created_at, they don't catch invalid date strings that fail to parse. Consider validating createdMs early:

🛡️ Proposed fix
 /** Parse updated_at safely; fall back to created_at if unparseable or earlier. */
 function effectiveEndMs(task: Task): number {
   const createdMs = new Date(task.created_at!).getTime()
+  if (Number.isNaN(createdMs)) return Number.NaN
   if (!task.updated_at) return createdMs
   const updatedMs = new Date(task.updated_at).getTime()
   if (Number.isNaN(updatedMs) || updatedMs < createdMs) return createdMs
   return updatedMs
 }

 function getBarWidth(task: Task, maxDurationMs: number): number {
-  if (!task.created_at || maxDurationMs <= 0) return 20
+  if (!task.created_at || maxDurationMs <= 0) return 20
+  const createdMs = new Date(task.created_at).getTime()
+  if (Number.isNaN(createdMs)) return 20
-  const durationMs = Math.max(0, effectiveEndMs(task) - new Date(task.created_at).getTime())
+  const durationMs = Math.max(0, effectiveEndMs(task) - createdMs)
   const pct = Math.max(20, Math.min(100, (durationMs / maxDurationMs) * 100))
   return pct
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/pages/agents/TaskHistoryBar.tsx` around lines 19 - 26, effectiveEndMs
currently assumes task.created_at parses to a valid timestamp; change it to
guard against a malformed created_at by checking Number.isNaN(createdMs) right
after computing createdMs and handling it: if createdMs is NaN then try to parse
task.updated_at and return that if valid, otherwise fall back to Date.now();
then continue the existing logic (parse updated_at into updatedMs, validate it
with Number.isNaN and compare to createdMs) so getBarWidth / formatDuration no
longer receive NaN values. Reference: function effectiveEndMs and the
updatedMs/createdMs variables.
🤖 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__/stores/agents.test.ts`:
- Around line 357-384: The test uses an unsafe `as any` on the seeded
`agentTasks`; add a properly typed task factory (e.g., create a
makeTask(overrides?: Partial<TaskSummary>): TaskSummary similar to
makeAgent/makePerformance) and use it to seed agentTasks in the clearDetail test
instead of `as any`; update the test to call makeTask({ id: 't1', title: 'Task',
... }) so useAgentsStore.setState(...) provides a correctly typed array for
clearDetail to clear.

---

Duplicate comments:
In `@web/src/pages/agents/TaskHistoryBar.tsx`:
- Around line 19-26: effectiveEndMs currently assumes task.created_at parses to
a valid timestamp; change it to guard against a malformed created_at by checking
Number.isNaN(createdMs) right after computing createdMs and handling it: if
createdMs is NaN then try to parse task.updated_at and return that if valid,
otherwise fall back to Date.now(); then continue the existing logic (parse
updated_at into updatedMs, validate it with Number.isNaN and compare to
createdMs) so getBarWidth / formatDuration no longer receive NaN values.
Reference: function effectiveEndMs and the updatedMs/createdMs variables.
🪄 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: adac24c8-5ec9-4532-9201-a1deb9c7fee4

📥 Commits

Reviewing files that changed from the base of the PR and between 366802d and b5bd49f.

📒 Files selected for processing (3)
  • web/src/__tests__/stores/agents.test.ts
  • web/src/pages/agents/TaskHistory.tsx
  • web/src/pages/agents/TaskHistoryBar.tsx
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: Build Backend
  • GitHub Check: Build Sandbox
  • GitHub Check: Dashboard Test
  • GitHub Check: Build Web
  • GitHub Check: Dependency Review
  • GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (1)
web/src/**/*.{tsx,ts}

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • web/src/pages/agents/TaskHistoryBar.tsx
  • web/src/pages/agents/TaskHistory.tsx
  • web/src/__tests__/stores/agents.test.ts
🧠 Learnings (6)
📓 Common learnings
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:20:09.993Z
Learning: Applies to web/src/components/** : Vue components organized by feature (agents/, approvals/, budget/, common/, dashboard/, layout/, messages/, org-chart/, tasks/).
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-17T22:08:13.456Z
Learning: Engine: Agent orchestration, execution loops, parallel execution, task decomposition, routing, task assignment, centralized single-writer task state engine (TaskEngine), task lifecycle, recovery, shutdown, workspace isolation, coordination (multi-agent pipeline: TopologyDispatcher protocol, 4 dispatchers — SAS/centralized/decentralized/context-dependent, wave execution, workspace lifecycle integration, CoordinationSectionConfig company config bridge, build_coordinator factory), coordination error classification, prompt policy validation, checkpoint recovery (checkpoint/, per-turn persistence, heartbeat detection, CheckpointRecoveryStrategy), approval gate (escalation detection, context parking/resume, EscalationInfo/ResumePayload models), stagnation detection (stagnation/, StagnationDetector protocol, ToolRepetitionDetector, dual-signal analysis, corrective prompt injection), agent runtime state (AgentRuntimeState, lightweight per-agent execution status for dashboard queries and recove...
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T12:41:55.315Z
Learning: Applies to web/src/**/*.{tsx,ts} : Always reuse existing components from `web/src/components/ui/` before creating new ones. Check the required component inventory (StatusBadge, MetricCard, Sparkline, SectionCard, AgentCard, DeptHealthBar, ProgressGauge, StatPill, Avatar, Button, Toast, Skeleton, EmptyState, ErrorBoundary, ConfirmDialog, CommandPalette, InlineEdit, AnimatedPresence, StaggerGroup, TaskStatusIndicator, PriorityBadge)
📚 Learning: 2026-03-27T12:41:55.315Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T12:41:55.315Z
Learning: Applies to web/src/**/*.{tsx,ts} : Always reuse existing components from `web/src/components/ui/` before creating new ones. Check the required component inventory (StatusBadge, MetricCard, Sparkline, SectionCard, AgentCard, DeptHealthBar, ProgressGauge, StatPill, Avatar, Button, Toast, Skeleton, EmptyState, ErrorBoundary, ConfirmDialog, CommandPalette, InlineEdit, AnimatedPresence, StaggerGroup, TaskStatusIndicator, PriorityBadge)

Applied to files:

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

Applied to files:

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

Applied to files:

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

Applied to files:

  • web/src/__tests__/stores/agents.test.ts
🪛 GitHub Check: Dashboard Lint
web/src/__tests__/stores/agents.test.ts

[failure] 362-362:
Unexpected any. Specify a different type

🔇 Additional comments (10)
web/src/pages/agents/TaskHistoryBar.tsx (1)

47-77: LGTM!

The component implementation is clean and follows the coding guidelines well:

  • Uses semantic Tailwind classes (bg-border, text-foreground, text-muted-foreground)
  • Proper typography tokens (font-sans, font-mono)
  • Good use of cn() utility for conditional class composition
  • The animate-pulse for active tasks provides nice visual feedback
web/src/pages/agents/TaskHistory.tsx (3)

1-6: Good use of existing UI components.

The imports correctly leverage the existing component inventory (SectionCard, EmptyState, StaggerGroup) rather than building custom card/empty layouts from scratch. As per coding guidelines: "Do NOT build card-with-header layouts from scratch -- use <SectionCard>."


13-28: LGTM!

The filtering, sorting, and maxDurationMs computation logic is well-implemented:

  • Line 16 correctly filters out tasks with missing or unparseable created_at
  • Lines 21-27 mirror the effectiveEndMs logic in TaskHistoryBar.tsx, ensuring consistent duration calculations
  • The fallback to createdMs when endMs is NaN or earlier than createdMs (line 25) properly handles edge cases
  • Initial value of 1 in the reducer (line 28) prevents division-by-zero in bar width calculations

30-48: LGTM!

The component rendering follows the coding guidelines well:

  • Uses SectionCard for the card-with-header layout
  • Uses EmptyState for the empty state display
  • The .map() callback is kept simple by extracting TaskHistoryBar as a separate component
  • Proper use of StaggerGroup/StaggerItem for staggered animations
  • Sensible limit of 20 tasks to prevent UI performance issues
web/src/__tests__/stores/agents.test.ts (6)

1-19: LGTM!

The ESM mocking pattern using vi.mock followed by await import is the correct approach for Vitest 4.x. All necessary API endpoints are properly mocked.


20-75: LGTM!

Well-structured factory helpers with sensible defaults and override support. The makeAgent and makePerformance functions provide complete fixtures matching the API types.


77-141: LGTM!

The beforeEach properly resets all state, and the fetchAgents tests comprehensively cover success, failure, and loading state transitions. The deferred promise pattern on lines 128-140 effectively tests the loading flag during the in-flight period.


143-264: LGTM!

Excellent coverage of the fetchAgentDetail behavior:

  • Parallel endpoint fetching (lines 144-160)
  • Graceful degradation for partial failures (lines 162-194)
  • Full failure handling (lines 196-208)
  • Staleness guard with controlled resolution order (lines 210-241)
  • clearDetail invalidation of in-flight responses (lines 243-263)

The deferred promise pattern effectively validates the _detailRequestName staleness guard in the store implementation.


266-323: LGTM!

The fetchMoreActivity tests properly cover:

  • Event appending with total update (lines 267-286)
  • MAX_ACTIVITIES cap enforcement at 100 items (lines 288-308)
  • Existing data preservation on failure (lines 310-322)

The timestamp generation now uses i % 24 ensuring valid hour components.


325-355: LGTM!

Simple and complete coverage of all filter setter actions.

Add makeTask(overrides) factory matching makeAgent/makePerformance
pattern. Removes the unsafe `as any` cast in the clearDetail test.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@Aureliolo Aureliolo temporarily deployed to cloudflare-preview March 27, 2026 13:57 — with GitHub Actions Inactive
@Aureliolo Aureliolo merged commit 62d7880 into main Mar 27, 2026
28 of 32 checks passed
@Aureliolo Aureliolo deleted the feat/agent-profiles-page branch March 27, 2026 14:28
@Aureliolo Aureliolo temporarily deployed to cloudflare-preview March 27, 2026 14:28 — 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

Development

Successfully merging this pull request may close these issues.

feat: Agent Profiles and Detail pages (biography, career, performance)

1 participant