Skip to content

refactor: Phase 2 Query Keys Standardization - Complete TanStack Query v5 patterns implementation#692

Merged
Wirasm merged 8 commits intomainfrom
refactor/phase-2-query-keys-standardization
Sep 18, 2025
Merged

refactor: Phase 2 Query Keys Standardization - Complete TanStack Query v5 patterns implementation#692
Wirasm merged 8 commits intomainfrom
refactor/phase-2-query-keys-standardization

Conversation

@Wirasm
Copy link
Copy Markdown
Collaborator

@Wirasm Wirasm commented Sep 17, 2025

Pull Request

Summary

Complete implementation of Phase 2 Query Keys Standardization, establishing consistent TanStack Query v5 patterns across all features following vertical slice architecture. This refactor ensures query keys mirror backend API structure exactly with no backward compatibility, providing a solid foundation for future development.

Changes Made

  • Refactored all query key factories to follow consistent patterns across 5 features
  • Relocated progress feature from knowledge/progress to top-level /features/progress
  • Implemented shared query patterns (DISABLED_QUERY_KEY, comprehensive STALE_TIMES)
  • Eliminated all hardcoded values - 100% using shared constants
  • Added comprehensive test coverage for progress hooks (10 new tests)
  • Created detailed documentation (QUERY_PATTERNS.md) for future implementations

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Performance improvement
  • Code refactoring

Affected Services

  • Frontend (React UI)
  • Server (FastAPI backend)
  • MCP Server (Model Context Protocol)
  • Agents (PydanticAI service)
  • Database (migrations/schema)
  • Docker/Infrastructure
  • Documentation site

Testing

  • All existing tests pass
  • Added new tests for new functionality
  • Manually tested affected user flows
  • Docker builds succeed for all services

Test Evidence

# All feature tests passing
npm run test:run src/features
# ✓ 81 tests passed (100% success rate)

# Progress feature tests
npm run test:run src/features/progress  
# ✓ 10 tests passed

# TypeScript compilation
npx tsc --noEmit
# 0 errors related to our changes

# Biome linting
npm run biome
# Fixed all issues introduced by refactoring

Checklist

  • My code follows the service architecture patterns
  • If using an AI coding assistant, I used the CLAUDE.md rules
  • I have added tests that prove my fix/feature works
  • All new and existing tests pass locally
  • My changes generate no new warnings
  • I have updated relevant documentation
  • I have verified no regressions in existing features

Breaking Changes

Cache Reset Required

  • Query key structure has changed - browser cache will reset on deployment
  • No backward compatibility maintained per CLAUDE.md guidelines

Import Path Changes

  • Progress imports moved: knowledge/progressprogress
  • Update any external references to progress components

Removed Methods

  • projectKeys.tasks() and projectKeys.taskCounts() removed
  • knowledgeKeys.summary() replaced with knowledgeKeys.summaries()
  • knowledgeKeys.details() removed (use detail())

Implementation Details

Query Key Factories Standardized (31 files changed)

Feature Changes Status
Projects Removed task-related keys ✅ Complete
Tasks Added dual nature (global + project-scoped) ✅ Complete
Knowledge Removed redundant methods ✅ Complete
Progress Moved to top-level feature ✅ Complete
Documents Full factory pattern ✅ Complete
MCP Consistent stale times ✅ Complete

Shared Patterns Implementation

STALE_TIMES = {
  instant: 0,        // Real-time data
  realtime: 3_000,   // Near real-time
  frequent: 5_000,   // Frequently changing
  normal: 30_000,    // Standard cache
  rare: 300_000,     // Rarely changing
  static: Infinity   // Never stale
}

Success Metrics Achieved

  • Zero TypeScript Errors - All files compile without errors
  • 100% Test Coverage - All query hook tests pass (81 total)
  • Consistent Patterns - Every feature follows same factory pattern
  • Clean Architecture - Vertical slices are self-contained
  • Backend Alignment - Query keys match API routes 1:1

Additional Notes

Documentation

Created comprehensive QUERY_PATTERNS.md guide including:

  • Core principles and patterns
  • Migration checklist
  • Common pitfalls to avoid
  • Testing strategies
  • Complete code examples

Performance Impact

  • Reduced API calls through proper cache configuration
  • Eliminated race conditions from double-layer caching (Phase 1)
  • Consistent stale times prevent unnecessary refetches

Related PRs


PRP Reference: PRPs/completed/story_phase_2_query_keys_standardization.md

Summary by CodeRabbit

  • New Features
    • Searchable ComboBox for task assignees supporting custom names, improved icons and truncated display.
  • Refactor
    • Unified caching/polling for fresher updates across features; polling tuned for responsiveness.
    • Knowledge summaries no longer include tags; card descriptions now prefer metadata descriptions.
    • Default task list page size reduced for smaller pages.
  • Documentation
    • Added standardized TanStack Query patterns guide.
  • Tests
    • New unit tests for progress, knowledge, and task query behaviors.

Standardize query keys across all features following vertical slice architecture,
ensuring they mirror backend API structure exactly with no backward compatibility.

Key Changes:
- Refactor all query key factories to follow consistent patterns
- Move progress feature from knowledge/progress to top-level /features/progress
- Create shared query patterns for consistency (DISABLED_QUERY_KEY, STALE_TIMES)
- Remove all hardcoded stale times and disabled keys
- Update all imports after progress feature relocation

Query Key Factories Standardized:
- projectKeys: removed task-related keys (tasks, taskCounts)
- taskKeys: added dual nature support (global via lists(), project-scoped via byProject())
- knowledgeKeys: removed redundant methods (details, summary)
- progressKeys: new top-level feature with consistent factory
- documentKeys: full factory pattern with versions support
- mcpKeys: complete with health endpoint

Shared Patterns Implementation:
- STALE_TIMES: instant (0), realtime (3s), frequent (5s), normal (30s), rare (5m), static (∞)
- DISABLED_QUERY_KEY: consistent disabled query pattern across all features
- Removed unused createQueryOptions helper

Testing:
- Added comprehensive tests for progress hooks
- Updated all test mocks to include new STALE_TIMES values
- All 81 feature tests passing

Documentation:
- Created QUERY_PATTERNS.md guide for future implementations
- Clear patterns, examples, and migration checklist

Breaking Changes:
- Progress imports moved from knowledge/progress to progress
- Query key structure changes (cache will reset)
- No backward compatibility maintained

Co-Authored-By: Claude <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Sep 17, 2025

Walkthrough

Standardizes TanStack Query patterns (DISABLED_QUERY_KEY, STALE_TIMES, key factories), refactors knowledge/progress/projects/tasks query keys and hooks (optimistic updates, smart polling), migrates task assignee to free-form with ComboBox UI, updates tests, and adjusts imports/exports and small server/docs changes. (49 words)

Changes

Cohort / File(s) Summary
Docs & Shared Patterns
PRPs/ai_docs/QUERY_PATTERNS.md, archon-ui-main/src/features/shared/queryPatterns.ts
Adds Query pattern documentation and exports DISABLED_QUERY_KEY and STALE_TIMES presets for unified disabled-state sentinel and stale-time semantics.
Knowledge: Keys, Hooks, Components, Services, Exports
archon-ui-main/src/features/knowledge/hooks/useKnowledgeQueries.ts, .../hooks/tests/useKnowledgeQueries.test.ts, .../components/KnowledgeCard.tsx, .../components/KnowledgeList.tsx, .../components/AddKnowledgeDialog.tsx, .../views/KnowledgeView.tsx, .../services/knowledgeService.ts, .../index.ts, .../types/index.ts
Reworks knowledge query-key API (detail, chunks(id, opts), codeExamples, summaries, summariesPrefix, sources); adopts DISABLED_QUERY_KEY and STALE_TIMES; updates optimistic update/invalidation targets; renames metadata.filename → metadata.file_name in flows; tests updated; import path changes; removed re-export of progress; updateKnowledgeItem typing widened to accept optional tags.
Progress: Polling & Keys
archon-ui-main/src/features/progress/hooks/useProgressQueries.ts, .../hooks/tests/useProgressQueries.test.ts, .../components/CrawlingProgress.tsx, .../components/KnowledgeCardProgress.tsx, .../services/progressService.ts
Refactors progress keys (list→lists, adds active, detail(id)), centralizes timers and smart polling via useSmartPolling, uses DISABLED_QUERY_KEY and STALE_TIMES, improves 404 handling and multi-item polling; adds tests and adjusts imports.
Projects: Queries, Documents, Exports, View
archon-ui-main/src/features/projects/hooks/useProjectQueries.ts, .../hooks/tests/useProjectQueries.test.ts, .../documents/hooks/useDocumentQueries.ts, .../hooks/index.ts, .../views/ProjectsView.tsx
Unifies project key shapes, moves document keys into documents feature (documentKeys exported), removes several project-level keys and useTaskCounts from project hooks, applies DISABLED_QUERY_KEY/STALE_TIMES, updates tests and import locations (ProjectsView now imports useTaskCounts from tasks).
Tasks: Hooks/Keys, UI, Schemas, Types
archon-ui-main/src/features/projects/tasks/hooks/useTaskQueries.ts, .../hooks/tests/useTaskQueries.test.ts, .../hooks/index.ts, .../components/EditableTableCell.tsx, .../components/TaskAssignee.tsx, .../components/TaskEditModal.tsx, .../schemas/index.ts, .../types/task.ts, .../types/index.ts
Reshapes taskKeys (static all, adds lists, detail, counts; retains byProject), adds useTaskCounts, migrates optimistic flows to byProject and counts invalidations, converts Assignee type to string with COMMON_ASSIGNEES, updates schema validation, replaces Select with ComboBox in several UIs, and updates tests.
UI Primitive: ComboBox
archon-ui-main/src/features/ui/primitives/combobox.tsx
Reimplements ComboBox with ARIA listbox/combobox semantics: adds ARIA props and disabled, keyboard navigation, custom-value support, loading state, focus/scroll handling, and improved accessibility.
MCP Hooks
archon-ui-main/src/features/mcp/hooks/useMcpQueries.ts
Adds mcpKeys.health() key and replaces hard-coded staleTime values with STALE_TIMES presets.
Python: Server and Tools
python/src/server/services/knowledge/knowledge_summary_service.py, python/src/mcp_server/features/tasks/task_tools.py
Removes top-level tags field from summary output (tags remain in metadata), broadens task assignee docstring/handling to free-form names, reduces DEFAULT_PAGE_SIZE from 50 → 10, and updates examples/docstrings.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor UI as UI Component
  participant Hook as useKnowledgeItemChunks
  participant QK as knowledgeKeys
  participant RQ as React Query
  participant API as Knowledge API

  UI->>Hook: useKnowledgeItemChunks(id, { domain, limit, offset })
  Hook->>QK: chunks(id, opts)
  alt id undefined
    Hook->>RQ: queryKey = DISABLED_QUERY_KEY (enabled: false)
    RQ-->>Hook: skip fetch
  else id provided
    Hook->>RQ: queryKey = ["knowledge", id, "chunks", opts]
    RQ->>API: GET /knowledge/<id>/chunks?domain=&limit=&offset=
    API-->>RQ: chunks[]
    RQ-->>Hook: data
  end
Loading
sequenceDiagram
  autonumber
  actor UI as UI
  participant Hook as useOperationProgress
  participant Keys as progressKeys
  participant RQ as React Query
  participant Poll as useSmartPolling
  participant API as Progress API

  UI->>Hook: useOperationProgress(id, { onComplete, onError })
  Hook->>Keys: detail(id)
  Hook->>Poll: get interval (visible/hidden aware)
  Hook->>RQ: queryKey=["progress","detail",id], staleTime=instant, refetchInterval=smart
  RQ->>API: GET /progress/<id>
  API-->>RQ: status (running|completed|error)
  alt completed
    Hook->>UI: onComplete(response)
    Hook->>RQ: schedule removeQueries(["progress","detail",id])
  else error
    Hook->>UI: onError(message)
    Hook->>RQ: schedule removeQueries(["progress","detail",id])
  else running
    RQ->>API: re-fetch on interval
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related PRs

Suggested reviewers

  • coleam00

Poem

A rabbit taps keys with a querying grin,
New keys and stale times make caches spin.
Combobox hops in where Select used to be,
Assignees roam free — type, pick, or agree.
Smart polls hum softly while tests nibble right. 🥕🐇

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Description Check ⚠️ Warning The PR description closely follows the repository template and is otherwise thorough, providing a clear summary, a detailed list of changes, testing evidence, checklist, and explicit breaking-change notes. However, the "Affected Services" section lists only Frontend while the changeset includes Python backend files (e.g., MCP/server code and server services), so the affected-services declaration is inaccurate and the description is incomplete for reviewers tracking backend impact. Update the "Affected Services" checkboxes to include Server and MCP Server, enumerate the backend files changed (for example python/src/mcp_server/... and python/src/server/...), and add backend test evidence (pytest/build output) plus any server-side migration or compatibility notes so reviewers can verify backend impact.
✅ Passed checks (2 passed)
Check name Status Explanation
Title Check ✅ Passed The title succinctly and accurately describes the primary work—standardizing query keys and completing TanStack Query v5 patterns—matching the changes and new documentation introduced in the PR. It is specific, uses a conventional "refactor:" prefix, and conveys the main intent to reviewers scanning history.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch refactor/phase-2-query-keys-standardization

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

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

Caution

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

⚠️ Outside diff range comments (3)
archon-ui-main/src/features/knowledge/hooks/tests/useKnowledgeQueries.test.ts (1)

124-131: Pre-population uses a different QueryClient.

You’re setting data on a new client, not the one used by QueryClientProvider, so the cache seed is ignored. Use the same instance.

-      const wrapper = createWrapper();
-      const { result } = renderHook(() => useDeleteKnowledgeItem(), { wrapper });
-
-      // Pre-populate cache
-      const queryClient = new QueryClient();
-      queryClient.setQueryData(knowledgeKeys.lists(), initialData);
+      const queryClient = new QueryClient({
+        defaultOptions: { queries: { retry: false }, mutations: { retry: false } },
+      });
+      const wrapper = ({ children }: { children: React.ReactNode }) =>
+        React.createElement(QueryClientProvider, { client: queryClient }, children);
+      const { result } = renderHook(() => useDeleteKnowledgeItem(), { wrapper });
+      // Pre-populate cache for this client
+      queryClient.setQueryData(knowledgeKeys.lists(), initialData);
archon-ui-main/src/features/knowledge/hooks/useKnowledgeQueries.ts (2)

143-158: Filter-blind optimistic writes pollute filtered caches

setQueriesData over all summaries adds the optimistic item to caches with incompatible filters (e.g., different knowledge_type/tags). Gate writes by each query’s filter.

-      queryClient.setQueriesData<KnowledgeItemsResponse>({ queryKey: knowledgeKeys.summaries() }, (old) => {
-        if (!old) {
-          return {
-            items: [optimisticItem],
-            total: 1,
-            page: 1,
-            per_page: 100,
-            pages: 1,
-          };
-        }
-        return {
-          ...old,
-          items: [optimisticItem, ...old.items],
-          total: old.total + 1,
-        };
-      });
+      const entries = queryClient.getQueriesData<KnowledgeItemsResponse>({
+        queryKey: knowledgeKeys.summariesPrefix(),
+      });
+      for (const [qk, data] of entries) {
+        const filter =
+          Array.isArray(qk) && typeof qk[2] === "object" ? (qk[2] as KnowledgeItemsFilter) : undefined;
+        const itemTags = (optimisticItem as any).tags ?? optimisticItem.metadata?.tags ?? [];
+        const matches =
+          !filter ||
+          (!filter.knowledge_type || filter.knowledge_type === optimisticItem.knowledge_type) &&
+          (!filter.source_type || filter.source_type === optimisticItem.source_type) &&
+          (!filter.tags?.length || filter.tags.every((t) => itemTags.includes(t))) &&
+          (!filter.search ||
+            `${optimisticItem.title} ${optimisticItem.url}`.toLowerCase().includes(filter.search.toLowerCase()));
+        if (!matches) continue;
+        if (!data) {
+          queryClient.setQueryData<KnowledgeItemsResponse>(qk, {
+            items: [optimisticItem],
+            total: 1,
+            page: 1,
+            per_page: 100,
+            pages: 1,
+          });
+        } else {
+          queryClient.setQueryData<KnowledgeItemsResponse>(qk, {
+            ...data,
+            items: [optimisticItem, ...data.items],
+            total: (data.total ?? data.items.length) + 1,
+          });
+        }
+      }

339-354: Repeat: filter-blind optimistic insert for uploads

Same issue as above when adding optimistic uploads to summaries; apply the filter-aware pattern here too.

-      queryClient.setQueriesData<KnowledgeItemsResponse>({ queryKey: knowledgeKeys.summaries() }, (old) => {
-        if (!old) {
-          return {
-            items: [optimisticItem],
-            total: 1,
-            page: 1,
-            per_page: 100,
-            pages: 1,
-          };
-        }
-        return {
-          ...old,
-          items: [optimisticItem, ...old.items],
-          total: old.total + 1,
-        };
-      });
+      const entries = queryClient.getQueriesData<KnowledgeItemsResponse>({
+        queryKey: knowledgeKeys.summariesPrefix(),
+      });
+      for (const [qk, data] of entries) {
+        const filter =
+          Array.isArray(qk) && typeof qk[2] === "object" ? (qk[2] as KnowledgeItemsFilter) : undefined;
+        const itemTags = (optimisticItem as any).tags ?? optimisticItem.metadata?.tags ?? [];
+        const matches =
+          !filter ||
+          (!filter.knowledge_type || filter.knowledge_type === optimisticItem.knowledge_type) &&
+          (!filter.source_type || filter.source_type === optimisticItem.source_type) &&
+          (!filter.tags?.length || filter.tags.every((t) => itemTags.includes(t))) &&
+          (!filter.search ||
+            `${optimisticItem.title} ${optimisticItem.url}`.toLowerCase().includes(filter.search.toLowerCase()));
+        if (!matches) continue;
+        if (!data) {
+          queryClient.setQueryData<KnowledgeItemsResponse>(qk, {
+            items: [optimisticItem],
+            total: 1,
+            page: 1,
+            per_page: 100,
+            pages: 1,
+          });
+        } else {
+          queryClient.setQueryData<KnowledgeItemsResponse>(qk, {
+            ...data,
+            items: [optimisticItem, ...data.items],
+            total: (data.total ?? data.items.length) + 1,
+          });
+        }
+      }
🧹 Nitpick comments (25)
archon-ui-main/src/features/knowledge/types/knowledge.ts (1)

36-37: Avoid ambiguity between item.tags and metadata.tags.

Having both can drift. Document precedence directly on the new field.

Apply this diff:

-  tags?: string[]; // Optional tags array
+  /** Mirrors metadata.tags. Prefer this field; metadata.tags is legacy and may be removed. */
+  tags?: string[];

Please confirm callers won’t read from both and that APIs populate a single source of truth.

archon-ui-main/src/features/mcp/hooks/useMcpQueries.ts (1)

2-14: Standardization to STALE_TIMES is good; minor tuning suggestion.

  • Keys and shared staleTime adoption look consistent.
  • Optional: make status “snappier” by using realtime (3s) if desired.

Apply this optional tweak:

-    staleTime: STALE_TIMES.frequent,
+    staleTime: STALE_TIMES.realtime,

Is mcpKeys.health() used in this PR or upcoming work? If not, consider adding a TODO or removing to avoid dead exports.

Also applies to: 24-24, 33-33, 46-46, 59-59

PRPs/ai_docs/QUERY_PATTERNS.md (1)

179-189: Fix markdownlint MD040: add languages to fenced code blocks.

Two code fences lack a language; use text for directory trees.

Apply this diff:

-```
+```text
 src/features/projects/
 ├── components/         # UI components
 ├── hooks/
 │   └── useProjectQueries.ts  # Query hooks & keys
 ├── services/
 │   └── projectService.ts     # API calls
 └── types/
     └── index.ts              # TypeScript types
-```
+```

-```
+```text
 src/features/projects/tasks/
 ├── components/
 ├── hooks/
 │   └── useTaskQueries.ts    # Own query keys!
 ├── services/
 └── types/
-```
+```

Also applies to: 192-200

archon-ui-main/src/features/projects/documents/hooks/useDocumentQueries.ts (1)

6-14: Adopts DISABLED_QUERY_KEY and key factory — add a staleTime per pattern.

Per QUERY_PATTERNS, prefer explicit STALE_TIMES.

Apply this diff:

-import { DISABLED_QUERY_KEY } from "../../../shared/queryPatterns";
+import { DISABLED_QUERY_KEY, STALE_TIMES } from "../../../shared/queryPatterns";
@@
   return useQuery({
     queryKey: projectId ? documentKeys.byProject(projectId) : DISABLED_QUERY_KEY,
@@
-    enabled: !!projectId,
+    enabled: !!projectId,
+    staleTime: STALE_TIMES.normal,
   });

Ensure invalidateQueries/setQueryData elsewhere use documentKeys.* to stay consistent.

Also applies to: 22-29

archon-ui-main/src/features/knowledge/components/KnowledgeList.tsx (1)

63-82: Avoid O(n·m) scans when matching active operations.

For large lists, repeatedly calling Array.find on activeOperations is avoidable. Consider memoizing a Map by source_id and/or URL for O(1) lookups.

archon-ui-main/src/features/knowledge/components/KnowledgeCard.tsx (1)

235-237: Preserve description fallback to avoid regressions.

Some items may still populate summary fields. Use a fallback chain.

Apply:

-              description={item.metadata?.description}
+              description={item.metadata?.description ?? item.summary ?? item.metadata?.summary}
archon-ui-main/src/features/projects/tasks/hooks/tests/useTaskQueries.test.ts (1)

6-6: Remove unused test import and mock, or add a dedicated test for useTaskCounts.

Currently, useTaskCounts and its service mock aren’t exercised in this file.

Apply to keep the test lean:

-import { taskKeys, useCreateTask, useProjectTasks, useTaskCounts } from "../useTaskQueries";
+import { taskKeys, useCreateTask, useProjectTasks } from "../useTaskQueries";
@@
   taskService: {
     getTasksByProject: vi.fn(),
-    getTaskCountsForAllProjects: vi.fn(),
     createTask: vi.fn(),
     updateTask: vi.fn(),
     deleteTask: vi.fn(),
   },

Or add a small test that calls useTaskCounts and asserts it hits taskService.getTaskCountsForAllProjects().

Also applies to: 12-13

archon-ui-main/src/features/progress/hooks/tests/useProgressQueries.test.ts (5)

2-2: Remove unused import.

act is not used.

-import { act, renderHook, waitFor } from "@testing-library/react";
+import { renderHook, waitFor } from "@testing-library/react";

58-65: Align test objects with ProgressResponse type.

details isn’t part of ProgressResponse (per types). Drop it or extend the type; otherwise TS strict builds will complain.

-        details: {},
+        // no extra fields
-        details: { result: "success" },
+        // no extra fields

Also applies to: 82-87


140-157: ActiveOperationsResponse mocks missing required fields.

Add count and timestamp to match the interface used by the hooks.

       const mockOperations: ActiveOperationsResponse = {
         operations: [
           { /* ... */ },
           { /* ... */ },
         ],
+        count: 2,
+        timestamp: new Date().toISOString(),
       };
       const mockOperations: ActiveOperationsResponse = {
         operations: [
           { /* ... */ },
         ],
+        count: 1,
+        timestamp: new Date().toISOString(),
       };
       const emptyResponse: ActiveOperationsResponse = {
         operations: [],
-        count: 0,
+        count: 0,
+        timestamp: new Date().toISOString(),
       };
       const mockOperations: ActiveOperationsResponse = {
         operations: [
           { /* ... */ },
         ],
-        count: 1,
+        count: 1,
+        timestamp: new Date().toISOString(),
       };

Also applies to: 186-196, 211-216, 231-242


128-135: Test the disabled query state more robustly.

Also assert that the underlying service wasn’t called to ensure disablement.

   expect(result.current.isLoading).toBe(false);
   expect(result.current.data).toBeUndefined();
+  const { progressService } = await import("../../services");
+  expect(progressService.getProgress).not.toHaveBeenCalled();

184-209: Consider adding a 404-threshold test.

Add a case that simulates 5 consecutive 404s to verify we surface “Operation no longer exists”.

archon-ui-main/src/features/progress/hooks/useProgressQueries.ts (7)

47-88: Pause polling when tab is hidden; integrate useSmartPolling.

Current polling runs in background tabs. Use useSmartPolling so refetchInterval becomes false when hidden and slower when unfocused, per repo guidelines.

-import { DISABLED_QUERY_KEY, STALE_TIMES } from "../../shared/queryPatterns";
+import { DISABLED_QUERY_KEY, STALE_TIMES } from "../../shared/queryPatterns";
+import { useSmartPolling } from "../../ui/hooks";
@@
 export function useOperationProgress(
   progressId: string | null,
   options?: {
@@
 ) {
   const queryClient = useQueryClient();
+  const { refetchInterval: smartInterval } = useSmartPolling(options?.pollingInterval ?? 1000);
@@
-    refetchInterval: (query) => {
+    refetchInterval: (query) => {
       const data = query.state.data as ProgressResponse | null | undefined;
       if (data && TERMINAL_STATES.includes(data.status)) {
         return false;
       }
-      return options?.pollingInterval ?? 1000;
+      return smartInterval;
     },

56-73: Avoid string-matching HTTP errors.

Prefer checking a status code field if available (e.g., error.status === 404 or error.response?.status === 404) to reduce false positives.

-        const errorMessage = error instanceof Error ? error.message : String(error);
-        if (errorMessage.includes("404") || errorMessage.includes("not found")) {
+        const status = (error as any)?.status ?? (error as any)?.response?.status;
+        const message = error instanceof Error ? error.message : String(error);
+        if (status === 404 || /not found/i.test(message)) {

90-150: Clear timeouts to avoid dangling timers.

Store timeout IDs and clear them on effect cleanup/unmount.

   useEffect(() => {
+    const timers: number[] = [];
     if (!query.data) return;
@@
-      setTimeout(() => {
+      timers.push(window.setTimeout(() => {
         if (progressId) {
           queryClient.removeQueries({ queryKey: progressKeys.detail(progressId) });
         }
-      }, 2000);
+      }, 2000));
@@
-      setTimeout(() => {
+      timers.push(window.setTimeout(() => {
         if (progressId) {
           queryClient.removeQueries({ queryKey: progressKeys.detail(progressId) });
         }
-      }, 2000);
+      }, 2000));
@@
-      setTimeout(() => {
+      timers.push(window.setTimeout(() => {
         if (progressId) {
           queryClient.removeQueries({ queryKey: progressKeys.detail(progressId) });
         }
-      }, 5000);
+      }, 5000));
     }
-  }, [query.data?.status, progressId, queryClient, options, query.data]);
+    return () => { timers.forEach(clearTimeout); };
+  }, [query.data?.status, progressId, queryClient, options, query.data]);

And similarly for the error-forwarding effect:

-  useEffect(() => {
+  useEffect(() => {
+    const timers: number[] = [];
@@
-    setTimeout(() => {
+    timers.push(window.setTimeout(() => {
       if (progressId) {
         queryClient.removeQueries({ queryKey: progressKeys.detail(progressId) });
       }
-    }, 5000);
+    }, 5000));
-  }, [query.error, progressId, queryClient, options]);
+    return () => { timers.forEach(clearTimeout); };
+  }, [query.error, progressId, queryClient, options]);

167-174: Adopt smart polling for active operations.

Use useSmartPolling so we don’t poll when hidden.

-export function useActiveOperations(enabled = false) {
-  return useQuery<ActiveOperationsResponse>({
+export function useActiveOperations(enabled = false) {
+  const { refetchInterval } = useSmartPolling(5000);
+  return useQuery<ActiveOperationsResponse>({
     queryKey: progressKeys.lists(),
     queryFn: () => progressService.listActiveOperations(),
     enabled,
-    refetchInterval: enabled ? 5000 : false, // Only poll when explicitly enabled
+    refetchInterval: enabled ? refetchInterval : false,
     staleTime: STALE_TIMES.realtime, // Near real-time for active operations
   });
 }

181-187: Adopt smart polling for crawl progress list.

Same rationale as above.

 export function useCrawlProgressPolling() {
-  const { data, isLoading } = useQuery({
+  const { refetchInterval } = useSmartPolling(5000);
+  const { data, isLoading } = useQuery({
     queryKey: progressKeys.lists(),
     queryFn: () => progressService.listActiveOperations(),
-    refetchInterval: 5000, // Poll every 5 seconds
+    refetchInterval,
     staleTime: STALE_TIMES.instant, // Always fresh for active progress
   });

202-263: Remove any and type useQueries results.

Avoid explicit any in strict TS. Type the array of query results.

-  const queries = (useQueries as any)({
-    queries: progressIds.map((progressId) => ({
+  const queries = useQueries({
+    queries: progressIds.map((progressId) => ({
       queryKey: progressKeys.detail(progressId) as readonly unknown[],
       queryFn: async (): Promise<ProgressResponse | null> => {
         /* ... */
       },
       refetchInterval: (query: { state: { data?: ProgressResponse } }) => {
         /* ... */
       },
       retry: false,
       staleTime: STALE_TIMES.instant, // Always fresh for real-time progress
     })),
-  });
+  }) as Array<import("@tanstack/react-query").UseQueryResult<ProgressResponse | null>>;

215-221: Stabilize dependency across reorderings.

progressIds.join(",") is order-sensitive and commas can collide. Prefer a sorted, JSON approach.

-  }, [progressIds.join(",")]); // Use join to create stable dependency
+  }, [JSON.stringify([...progressIds].sort())]);
archon-ui-main/src/features/projects/tasks/hooks/useTaskQueries.ts (1)

60-69: Avoid defaulting domain fields to sentinel values.

assignee: "User" may conflict with real user semantics. Prefer undefined (let server assign) unless the API requires a value.

-        assignee: newTaskData.assignee ?? "User",
+        assignee: newTaskData.assignee,
archon-ui-main/src/features/projects/hooks/useProjectQueries.ts (1)

31-38: Disable + sentinel pattern is correct; consider typing the query.

Provide a generic to useQuery for stronger types.

-export function useProjectFeatures(projectId: string | undefined) {
-  return useQuery({
+export function useProjectFeatures(projectId: string | undefined) {
+  return useQuery<Awaited<ReturnType<typeof projectService.getProjectFeatures>>>({
     queryKey: projectId ? projectKeys.features(projectId) : DISABLED_QUERY_KEY,
     queryFn: () => (projectId ? projectService.getProjectFeatures(projectId) : Promise.reject("No project ID")),
     enabled: !!projectId,
     staleTime: STALE_TIMES.normal,
   });
 }
archon-ui-main/src/features/knowledge/hooks/useKnowledgeQueries.ts (4)

722-730: Use shared STALE_TIMES in polling and staleTime

Replace magic numbers with the shared constants for consistency.

-  const { refetchInterval } = useSmartPolling(hasActiveOperations ? 5000 : 30000);
+  const { refetchInterval } = useSmartPolling(
+    hasActiveOperations ? STALE_TIMES.frequent : STALE_TIMES.normal,
+  );
@@
-    staleTime: 30000, // Consider data stale after 30 seconds
+    staleTime: STALE_TIMES.normal, // Consider data stale after 30 seconds

115-116: Guard URL parsing for optimistic title

new URL() throws on invalid input; avoid exceptions during optimistic updates.

-        title: new URL(request.url).hostname || "New crawl",
+        title: (() => {
+          try {
+            return new URL(request.url).hostname || "New crawl";
+          } catch {
+            return "New crawl";
+          }
+        })(),

570-571: Avoid any; update tags with proper typing

Use the typed tags?: string[] on KnowledgeItem; remove as any.

-          const newTags = updates.tags as string[];
-          (updatedItem as any).tags = newTags;
+          const newTags = updates.tags as string[];
+          updatedItem.tags = newTags;
@@
-        updatedItem.metadata = {
+        updatedItem.metadata = {
           ...currentMetadata,
-          ...((updatedItem as any).tags && { tags: (updatedItem as any).tags }),
+          ...(updatedItem.tags && { tags: updatedItem.tags }),
           ...(updatedItem.knowledge_type && { knowledge_type: updatedItem.knowledge_type }),
         };

Also applies to: 582-584


251-253: Also invalidate summaries after starting a crawl

Ensures summaries refresh promptly even if polling hasn’t kicked in yet.

       // Invalidate to get fresh data
       queryClient.invalidateQueries({ queryKey: knowledgeKeys.lists() });
+      queryClient.invalidateQueries({ queryKey: knowledgeKeys.summariesPrefix() });
       queryClient.invalidateQueries({ queryKey: progressKeys.lists() });
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b383c8c and 3c902ae.

📒 Files selected for processing (25)
  • PRPs/ai_docs/QUERY_PATTERNS.md (1 hunks)
  • archon-ui-main/src/features/knowledge/components/AddKnowledgeDialog.tsx (1 hunks)
  • archon-ui-main/src/features/knowledge/components/KnowledgeCard.tsx (2 hunks)
  • archon-ui-main/src/features/knowledge/components/KnowledgeList.tsx (1 hunks)
  • archon-ui-main/src/features/knowledge/hooks/tests/useKnowledgeQueries.test.ts (2 hunks)
  • archon-ui-main/src/features/knowledge/hooks/useKnowledgeQueries.ts (28 hunks)
  • archon-ui-main/src/features/knowledge/index.ts (0 hunks)
  • archon-ui-main/src/features/knowledge/types/index.ts (0 hunks)
  • archon-ui-main/src/features/knowledge/types/knowledge.ts (1 hunks)
  • archon-ui-main/src/features/knowledge/views/KnowledgeView.tsx (1 hunks)
  • archon-ui-main/src/features/mcp/hooks/useMcpQueries.ts (6 hunks)
  • archon-ui-main/src/features/progress/components/CrawlingProgress.tsx (1 hunks)
  • archon-ui-main/src/features/progress/components/KnowledgeCardProgress.tsx (1 hunks)
  • archon-ui-main/src/features/progress/hooks/tests/useProgressQueries.test.ts (1 hunks)
  • archon-ui-main/src/features/progress/hooks/useProgressQueries.ts (6 hunks)
  • archon-ui-main/src/features/progress/services/progressService.ts (1 hunks)
  • archon-ui-main/src/features/projects/documents/hooks/useDocumentQueries.ts (2 hunks)
  • archon-ui-main/src/features/projects/hooks/index.ts (0 hunks)
  • archon-ui-main/src/features/projects/hooks/tests/useProjectQueries.test.ts (1 hunks)
  • archon-ui-main/src/features/projects/hooks/useProjectQueries.ts (2 hunks)
  • archon-ui-main/src/features/projects/tasks/hooks/index.ts (1 hunks)
  • archon-ui-main/src/features/projects/tasks/hooks/tests/useTaskQueries.test.ts (2 hunks)
  • archon-ui-main/src/features/projects/tasks/hooks/useTaskQueries.ts (10 hunks)
  • archon-ui-main/src/features/projects/views/ProjectsView.tsx (1 hunks)
  • archon-ui-main/src/features/shared/queryPatterns.ts (1 hunks)
💤 Files with no reviewable changes (3)
  • archon-ui-main/src/features/knowledge/index.ts
  • archon-ui-main/src/features/projects/hooks/index.ts
  • archon-ui-main/src/features/knowledge/types/index.ts
🧰 Additional context used
📓 Path-based instructions (5)
archon-ui-main/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

archon-ui-main/src/**/*.{ts,tsx}: Use TanStack Query for all data fetching; avoid prop drilling
TypeScript: strict mode with no implicit any in frontend code
State naming: is[Action]ing for loading flags, [resource]Error for errors, selected[Resource] for current selection
Use HTTP polling with ETag caching; do not introduce WebSocket-based updates in the frontend

archon-ui-main/src/**/*.{ts,tsx}: WebSocket event failures (if any) should be logged and not crash the client; continue serving others
Frontend data fetching must use TanStack Query (no prop drilling) with query key factories, smart polling, and optimistic updates with rollback
Use vertical slice architecture: place UI under src/features/[feature]/(components|hooks|services|types)
State naming: use is[Action]ing for loading, [resource]Error for errors, selected[Resource] for selections
Service method names: get[Resource]sByProject(projectId), getResource, create/update/delete patterns
Frontend TypeScript should be strict (no implicit any)

Files:

  • archon-ui-main/src/features/progress/hooks/tests/useProgressQueries.test.ts
  • archon-ui-main/src/features/knowledge/types/knowledge.ts
  • archon-ui-main/src/features/knowledge/views/KnowledgeView.tsx
  • archon-ui-main/src/features/progress/components/KnowledgeCardProgress.tsx
  • archon-ui-main/src/features/progress/components/CrawlingProgress.tsx
  • archon-ui-main/src/features/mcp/hooks/useMcpQueries.ts
  • archon-ui-main/src/features/knowledge/components/KnowledgeList.tsx
  • archon-ui-main/src/features/projects/hooks/tests/useProjectQueries.test.ts
  • archon-ui-main/src/features/projects/tasks/hooks/index.ts
  • archon-ui-main/src/features/shared/queryPatterns.ts
  • archon-ui-main/src/features/progress/services/progressService.ts
  • archon-ui-main/src/features/knowledge/components/KnowledgeCard.tsx
  • archon-ui-main/src/features/projects/views/ProjectsView.tsx
  • archon-ui-main/src/features/projects/tasks/hooks/useTaskQueries.ts
  • archon-ui-main/src/features/projects/tasks/hooks/tests/useTaskQueries.test.ts
  • archon-ui-main/src/features/progress/hooks/useProgressQueries.ts
  • archon-ui-main/src/features/projects/hooks/useProjectQueries.ts
  • archon-ui-main/src/features/projects/documents/hooks/useDocumentQueries.ts
  • archon-ui-main/src/features/knowledge/hooks/useKnowledgeQueries.ts
  • archon-ui-main/src/features/knowledge/hooks/tests/useKnowledgeQueries.test.ts
  • archon-ui-main/src/features/knowledge/components/AddKnowledgeDialog.tsx
archon-ui-main/src/features/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

archon-ui-main/src/features/**/*.{ts,tsx}: Follow TanStack Query patterns: query-keys factory, smart polling via useSmartPolling, optimistic updates with rollback
Biome formatting in features: 120-character lines, double quotes, trailing commas

archon-ui-main/src/features/**/*.{ts,tsx}: Use Biome formatting/conventions in /src/features: 120-char lines, double quotes, trailing commas
Use useSmartPolling and polling intervals (1–2s active, 5–10s background) with smart pausing on tab inactivity
Expose progress via dedicated hooks (e.g., useCrawlProgressPolling, useProjectTasks) instead of ad-hoc timers
Do not use prop drilling for data fetching/state; rely on TanStack Query caches/selectors

Files:

  • archon-ui-main/src/features/progress/hooks/tests/useProgressQueries.test.ts
  • archon-ui-main/src/features/knowledge/types/knowledge.ts
  • archon-ui-main/src/features/knowledge/views/KnowledgeView.tsx
  • archon-ui-main/src/features/progress/components/KnowledgeCardProgress.tsx
  • archon-ui-main/src/features/progress/components/CrawlingProgress.tsx
  • archon-ui-main/src/features/mcp/hooks/useMcpQueries.ts
  • archon-ui-main/src/features/knowledge/components/KnowledgeList.tsx
  • archon-ui-main/src/features/projects/hooks/tests/useProjectQueries.test.ts
  • archon-ui-main/src/features/projects/tasks/hooks/index.ts
  • archon-ui-main/src/features/shared/queryPatterns.ts
  • archon-ui-main/src/features/progress/services/progressService.ts
  • archon-ui-main/src/features/knowledge/components/KnowledgeCard.tsx
  • archon-ui-main/src/features/projects/views/ProjectsView.tsx
  • archon-ui-main/src/features/projects/tasks/hooks/useTaskQueries.ts
  • archon-ui-main/src/features/projects/tasks/hooks/tests/useTaskQueries.test.ts
  • archon-ui-main/src/features/progress/hooks/useProgressQueries.ts
  • archon-ui-main/src/features/projects/hooks/useProjectQueries.ts
  • archon-ui-main/src/features/projects/documents/hooks/useDocumentQueries.ts
  • archon-ui-main/src/features/knowledge/hooks/useKnowledgeQueries.ts
  • archon-ui-main/src/features/knowledge/hooks/tests/useKnowledgeQueries.test.ts
  • archon-ui-main/src/features/knowledge/components/AddKnowledgeDialog.tsx
**/*.{py,ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Never return None/null to indicate failure; raise an exception with details instead

Files:

  • archon-ui-main/src/features/progress/hooks/tests/useProgressQueries.test.ts
  • archon-ui-main/src/features/knowledge/types/knowledge.ts
  • archon-ui-main/src/features/knowledge/views/KnowledgeView.tsx
  • archon-ui-main/src/features/progress/components/KnowledgeCardProgress.tsx
  • archon-ui-main/src/features/progress/components/CrawlingProgress.tsx
  • archon-ui-main/src/features/mcp/hooks/useMcpQueries.ts
  • archon-ui-main/src/features/knowledge/components/KnowledgeList.tsx
  • archon-ui-main/src/features/projects/hooks/tests/useProjectQueries.test.ts
  • archon-ui-main/src/features/projects/tasks/hooks/index.ts
  • archon-ui-main/src/features/shared/queryPatterns.ts
  • archon-ui-main/src/features/progress/services/progressService.ts
  • archon-ui-main/src/features/knowledge/components/KnowledgeCard.tsx
  • archon-ui-main/src/features/projects/views/ProjectsView.tsx
  • archon-ui-main/src/features/projects/tasks/hooks/useTaskQueries.ts
  • archon-ui-main/src/features/projects/tasks/hooks/tests/useTaskQueries.test.ts
  • archon-ui-main/src/features/progress/hooks/useProgressQueries.ts
  • archon-ui-main/src/features/projects/hooks/useProjectQueries.ts
  • archon-ui-main/src/features/projects/documents/hooks/useDocumentQueries.ts
  • archon-ui-main/src/features/knowledge/hooks/useKnowledgeQueries.ts
  • archon-ui-main/src/features/knowledge/hooks/tests/useKnowledgeQueries.test.ts
  • archon-ui-main/src/features/knowledge/components/AddKnowledgeDialog.tsx
archon-ui-main/src/**/*.{test,spec}.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Write frontend tests with Vitest and React Testing Library

Files:

  • archon-ui-main/src/features/progress/hooks/tests/useProgressQueries.test.ts
  • archon-ui-main/src/features/projects/hooks/tests/useProjectQueries.test.ts
  • archon-ui-main/src/features/projects/tasks/hooks/tests/useTaskQueries.test.ts
  • archon-ui-main/src/features/knowledge/hooks/tests/useKnowledgeQueries.test.ts
archon-ui-main/src/features/**/services/**/*.ts

📄 CodeRabbit inference engine (AGENTS.md)

Frontend service method naming: get[Resource]sByProject(projectId), getResource, createResource, update[Resource](id, updates), deleteResource

Files:

  • archon-ui-main/src/features/progress/services/progressService.ts
🧠 Learnings (14)
📓 Common learnings
Learnt from: CR
PR: coleam00/Archon#0
File: AGENTS.md:0-0
Timestamp: 2025-09-12T13:47:04.545Z
Learning: Applies to archon-ui-main/src/features/**/*.{ts,tsx} : Follow TanStack Query patterns: query-keys factory, smart polling via useSmartPolling, optimistic updates with rollback
Learnt from: CR
PR: coleam00/Archon#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-13T15:53:40.757Z
Learning: Applies to archon-ui-main/src/**/*.{ts,tsx} : Frontend data fetching must use TanStack Query (no prop drilling) with query key factories, smart polling, and optimistic updates with rollback
📚 Learning: 2025-09-13T15:53:40.757Z
Learnt from: CR
PR: coleam00/Archon#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-13T15:53:40.757Z
Learning: Applies to archon-ui-main/src/features/**/*.{ts,tsx} : Expose progress via dedicated hooks (e.g., useCrawlProgressPolling, useProjectTasks) instead of ad-hoc timers

Applied to files:

  • archon-ui-main/src/features/progress/hooks/tests/useProgressQueries.test.ts
  • archon-ui-main/src/features/knowledge/views/KnowledgeView.tsx
  • archon-ui-main/src/features/progress/components/KnowledgeCardProgress.tsx
  • archon-ui-main/src/features/progress/components/CrawlingProgress.tsx
  • archon-ui-main/src/features/projects/hooks/tests/useProjectQueries.test.ts
  • archon-ui-main/src/features/projects/tasks/hooks/index.ts
  • archon-ui-main/src/features/progress/services/progressService.ts
  • archon-ui-main/src/features/projects/views/ProjectsView.tsx
  • archon-ui-main/src/features/projects/tasks/hooks/useTaskQueries.ts
  • archon-ui-main/src/features/projects/tasks/hooks/tests/useTaskQueries.test.ts
  • archon-ui-main/src/features/progress/hooks/useProgressQueries.ts
  • archon-ui-main/src/features/projects/hooks/useProjectQueries.ts
📚 Learning: 2025-09-12T13:47:04.545Z
Learnt from: CR
PR: coleam00/Archon#0
File: AGENTS.md:0-0
Timestamp: 2025-09-12T13:47:04.545Z
Learning: Applies to archon-ui-main/src/features/**/*.{ts,tsx} : Follow TanStack Query patterns: query-keys factory, smart polling via useSmartPolling, optimistic updates with rollback

Applied to files:

  • archon-ui-main/src/features/progress/hooks/tests/useProgressQueries.test.ts
  • archon-ui-main/src/features/knowledge/views/KnowledgeView.tsx
  • archon-ui-main/src/features/progress/components/KnowledgeCardProgress.tsx
  • archon-ui-main/src/features/progress/components/CrawlingProgress.tsx
  • archon-ui-main/src/features/mcp/hooks/useMcpQueries.ts
  • archon-ui-main/src/features/projects/hooks/tests/useProjectQueries.test.ts
  • archon-ui-main/src/features/shared/queryPatterns.ts
  • PRPs/ai_docs/QUERY_PATTERNS.md
  • archon-ui-main/src/features/projects/views/ProjectsView.tsx
  • archon-ui-main/src/features/projects/tasks/hooks/useTaskQueries.ts
  • archon-ui-main/src/features/projects/tasks/hooks/tests/useTaskQueries.test.ts
  • archon-ui-main/src/features/progress/hooks/useProgressQueries.ts
  • archon-ui-main/src/features/projects/hooks/useProjectQueries.ts
  • archon-ui-main/src/features/projects/documents/hooks/useDocumentQueries.ts
  • archon-ui-main/src/features/knowledge/hooks/useKnowledgeQueries.ts
  • archon-ui-main/src/features/knowledge/hooks/tests/useKnowledgeQueries.test.ts
📚 Learning: 2025-08-28T13:07:24.810Z
Learnt from: Wirasm
PR: coleam00/Archon#514
File: archon-ui-main/src/services/crawlProgressService.ts:35-39
Timestamp: 2025-08-28T13:07:24.810Z
Learning: The crawlProgressService.ts in the Archon codebase should be deprecated in favor of the existing useCrawlProgressPolling hook from usePolling.ts, which already includes ETag support, 304 handling, tab visibility detection, and proper React lifecycle integration. This consolidation reduces code duplication and improves performance.

Applied to files:

  • archon-ui-main/src/features/progress/hooks/tests/useProgressQueries.test.ts
  • archon-ui-main/src/features/progress/components/CrawlingProgress.tsx
  • archon-ui-main/src/features/progress/services/progressService.ts
  • archon-ui-main/src/features/progress/hooks/useProgressQueries.ts
📚 Learning: 2025-08-29T08:57:47.558Z
Learnt from: Wirasm
PR: coleam00/Archon#514
File: archon-ui-main/src/services/progressService.ts:0-0
Timestamp: 2025-08-29T08:57:47.558Z
Learning: The progressService.ts file was removed from the codebase in PR #514 as part of the consolidation effort to use the usePolling hook pattern from usePolling.ts instead of maintaining separate polling services. This aligns with the architectural decision to deprecate individual polling services in favor of the centralized hook-based approach.

Applied to files:

  • archon-ui-main/src/features/progress/hooks/tests/useProgressQueries.test.ts
  • archon-ui-main/src/features/progress/components/CrawlingProgress.tsx
  • archon-ui-main/src/features/progress/services/progressService.ts
  • archon-ui-main/src/features/progress/hooks/useProgressQueries.ts
📚 Learning: 2025-09-13T15:53:40.757Z
Learnt from: CR
PR: coleam00/Archon#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-13T15:53:40.757Z
Learning: Applies to archon-ui-main/src/**/*.{ts,tsx} : Frontend data fetching must use TanStack Query (no prop drilling) with query key factories, smart polling, and optimistic updates with rollback

Applied to files:

  • archon-ui-main/src/features/progress/hooks/tests/useProgressQueries.test.ts
  • archon-ui-main/src/features/mcp/hooks/useMcpQueries.ts
  • archon-ui-main/src/features/shared/queryPatterns.ts
  • PRPs/ai_docs/QUERY_PATTERNS.md
  • archon-ui-main/src/features/projects/views/ProjectsView.tsx
  • archon-ui-main/src/features/projects/tasks/hooks/useTaskQueries.ts
  • archon-ui-main/src/features/progress/hooks/useProgressQueries.ts
  • archon-ui-main/src/features/projects/hooks/useProjectQueries.ts
  • archon-ui-main/src/features/knowledge/hooks/useKnowledgeQueries.ts
📚 Learning: 2025-09-13T15:53:40.757Z
Learnt from: CR
PR: coleam00/Archon#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-13T15:53:40.757Z
Learning: Applies to archon-ui-main/src/**/*.{test,spec}.{ts,tsx} : Write frontend tests with Vitest and React Testing Library

Applied to files:

  • archon-ui-main/src/features/progress/hooks/tests/useProgressQueries.test.ts
  • archon-ui-main/src/features/projects/tasks/hooks/tests/useTaskQueries.test.ts
📚 Learning: 2025-08-28T13:11:24.805Z
Learnt from: Wirasm
PR: coleam00/Archon#514
File: archon-ui-main/src/services/crawlProgressService.ts:36-39
Timestamp: 2025-08-28T13:11:24.805Z
Learning: The crawlProgressService.ts file had NodeJS.Timeout type annotations that should be replaced with ReturnType<typeof setInterval> for better TypeScript compatibility across Node.js and browser environments, especially important for frontend services that need to work in web applications.

Applied to files:

  • archon-ui-main/src/features/progress/components/CrawlingProgress.tsx
📚 Learning: 2025-09-13T15:53:40.757Z
Learnt from: CR
PR: coleam00/Archon#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-13T15:53:40.757Z
Learning: Applies to archon-ui-main/src/features/**/*.{ts,tsx} : Use useSmartPolling and polling intervals (1–2s active, 5–10s background) with smart pausing on tab inactivity

Applied to files:

  • archon-ui-main/src/features/mcp/hooks/useMcpQueries.ts
📚 Learning: 2025-09-13T15:53:40.757Z
Learnt from: CR
PR: coleam00/Archon#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-13T15:53:40.757Z
Learning: Applies to archon-ui-main/src/**/*.{ts,tsx} : Service method names: get[Resource]sByProject(projectId), get[Resource](id), create/update/delete patterns

Applied to files:

  • archon-ui-main/src/features/projects/hooks/tests/useProjectQueries.test.ts
  • archon-ui-main/src/features/projects/views/ProjectsView.tsx
📚 Learning: 2025-09-13T15:53:40.757Z
Learnt from: CR
PR: coleam00/Archon#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-13T15:53:40.757Z
Learning: Applies to archon-ui-main/src/features/**/*.{ts,tsx} : Do not use prop drilling for data fetching/state; rely on TanStack Query caches/selectors

Applied to files:

  • archon-ui-main/src/features/shared/queryPatterns.ts
  • PRPs/ai_docs/QUERY_PATTERNS.md
📚 Learning: 2025-09-12T13:47:04.545Z
Learnt from: CR
PR: coleam00/Archon#0
File: AGENTS.md:0-0
Timestamp: 2025-09-12T13:47:04.545Z
Learning: Applies to archon-ui-main/src/**/*.{ts,tsx} : Use TanStack Query for all data fetching; avoid prop drilling

Applied to files:

  • archon-ui-main/src/features/shared/queryPatterns.ts
  • PRPs/ai_docs/QUERY_PATTERNS.md
📚 Learning: 2025-09-12T13:47:04.545Z
Learnt from: CR
PR: coleam00/Archon#0
File: AGENTS.md:0-0
Timestamp: 2025-09-12T13:47:04.545Z
Learning: Applies to archon-ui-main/src/**/*.{ts,tsx} : Use HTTP polling with ETag caching; do not introduce WebSocket-based updates in the frontend

Applied to files:

  • archon-ui-main/src/features/progress/services/progressService.ts
📚 Learning: 2025-08-28T12:56:47.840Z
Learnt from: Wirasm
PR: coleam00/Archon#514
File: archon-ui-main/src/pages/ProjectPage.tsx:329-331
Timestamp: 2025-08-28T12:56:47.840Z
Learning: In the ProjectPage.tsx polling refactor, temporary project creation logic with progress cards was removed in favor of simpler modal loading states, as the complexity of managing in-flight temporary projects wasn't justified when HTTP polling would show new projects within seconds anyway.

Applied to files:

  • archon-ui-main/src/features/projects/views/ProjectsView.tsx
  • archon-ui-main/src/features/projects/hooks/useProjectQueries.ts
🧬 Code graph analysis (10)
archon-ui-main/src/features/progress/hooks/tests/useProgressQueries.test.ts (3)
archon-ui-main/src/features/progress/hooks/useProgressQueries.ts (4)
  • progressKeys (13-18)
  • useOperationProgress (27-160)
  • useActiveOperations (167-175)
  • useCrawlProgressPolling (181-196)
archon-ui-main/src/features/progress/types/progress.ts (2)
  • ProgressResponse (111-149)
  • ActiveOperationsResponse (105-109)
archon-ui-main/src/features/progress/services/progressService.ts (1)
  • progressService (9-24)
archon-ui-main/src/features/mcp/hooks/useMcpQueries.ts (1)
archon-ui-main/src/features/shared/queryPatterns.ts (1)
  • STALE_TIMES (17-24)
archon-ui-main/src/features/projects/hooks/tests/useProjectQueries.test.ts (2)
archon-ui-main/src/features/projects/hooks/useProjectQueries.ts (1)
  • projectKeys (9-16)
archon-ui-main/src/features/projects/hooks/index.ts (1)
  • projectKeys (13-13)
archon-ui-main/src/features/projects/tasks/hooks/useTaskQueries.ts (2)
archon-ui-main/src/features/ui/hooks/useSmartPolling.ts (1)
  • useSmartPolling (8-66)
archon-ui-main/src/features/shared/queryPatterns.ts (2)
  • DISABLED_QUERY_KEY (13-13)
  • STALE_TIMES (17-24)
archon-ui-main/src/features/projects/tasks/hooks/tests/useTaskQueries.test.ts (1)
archon-ui-main/src/features/projects/tasks/hooks/useTaskQueries.ts (1)
  • taskKeys (9-15)
archon-ui-main/src/features/progress/hooks/useProgressQueries.ts (2)
archon-ui-main/src/features/shared/queryPatterns.ts (2)
  • DISABLED_QUERY_KEY (13-13)
  • STALE_TIMES (17-24)
archon-ui-main/src/features/progress/services/progressService.ts (1)
  • progressService (9-24)
archon-ui-main/src/features/projects/hooks/useProjectQueries.ts (1)
archon-ui-main/src/features/shared/queryPatterns.ts (2)
  • STALE_TIMES (17-24)
  • DISABLED_QUERY_KEY (13-13)
archon-ui-main/src/features/projects/documents/hooks/useDocumentQueries.ts (1)
archon-ui-main/src/features/shared/queryPatterns.ts (1)
  • DISABLED_QUERY_KEY (13-13)
archon-ui-main/src/features/knowledge/hooks/useKnowledgeQueries.ts (5)
archon-ui-main/src/features/knowledge/types/knowledge.ts (3)
  • KnowledgeItemsFilter (128-135)
  • KnowledgeItem (26-40)
  • KnowledgeItemsResponse (99-104)
archon-ui-main/src/features/shared/queryPatterns.ts (2)
  • DISABLED_QUERY_KEY (13-13)
  • STALE_TIMES (17-24)
archon-ui-main/src/features/knowledge/services/knowledgeService.ts (1)
  • knowledgeService (23-217)
archon-ui-main/src/features/progress/hooks/useProgressQueries.ts (1)
  • progressKeys (13-18)
archon-ui-main/src/features/progress/types/progress.ts (1)
  • ActiveOperationsResponse (105-109)
archon-ui-main/src/features/knowledge/hooks/tests/useKnowledgeQueries.test.ts (1)
archon-ui-main/src/features/knowledge/hooks/useKnowledgeQueries.ts (1)
  • knowledgeKeys (26-35)
🪛 markdownlint-cli2 (0.17.2)
PRPs/ai_docs/QUERY_PATTERNS.md

179-179: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


192-192: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🔇 Additional comments (20)
archon-ui-main/src/features/knowledge/components/AddKnowledgeDialog.tsx (1)

12-12: Import cleanup aligns with usage (no TabsList/TabsTrigger).

LGTM. Confirm there are no remaining references to TabsList/TabsTrigger in this feature.

archon-ui-main/src/features/shared/queryPatterns.ts (1)

1-24: Centralized DISABLED_QUERY_KEY and STALE_TIMES — solid foundation.

Immutable constants with “as const” are correct and align with the documented patterns.

archon-ui-main/src/features/progress/components/CrawlingProgress.tsx (1)

10-12: Import path updates — OK.

Matches the feature reorg; no behavior change.

archon-ui-main/src/features/progress/components/KnowledgeCardProgress.tsx (1)

9-9: cn import path tweak — OK.

No functional impact.

archon-ui-main/src/features/knowledge/components/KnowledgeList.tsx (1)

9-9: Type import path change LGTM.

archon-ui-main/src/features/projects/hooks/tests/useProjectQueries.test.ts (1)

55-61: Updated features key expectation matches the new factory shape.

archon-ui-main/src/features/knowledge/views/KnowledgeView.tsx (1)

13-14: Import relocations to progress feature LGTM.

archon-ui-main/src/features/projects/tasks/hooks/index.ts (1)

12-20: Exporting useTaskCounts from the tasks slice is the right boundary.

archon-ui-main/src/features/knowledge/components/KnowledgeCard.tsx (1)

11-12: Progress imports moved under the progress feature LGTM.

archon-ui-main/src/features/projects/tasks/hooks/tests/useTaskQueries.test.ts (1)

58-63: New taskKeys shape is consistent and scoped.

Static root ["tasks"], plus builders for lists/detail/byProject/counts are clear and align with the PR’s key standardization.

archon-ui-main/src/features/projects/views/ProjectsView.tsx (1)

12-14: Importing useTaskCounts from tasks/hooks — approved.
Verified: ProjectsView imports useTaskCounts from ../tasks/hooks and there are no remaining imports of useTaskCounts from ../hooks/useProjectQueries in archon-ui-main/src.

archon-ui-main/src/features/progress/services/progressService.ts (1)

6-23: Import path update LGTM — no legacy polling reintroduced

progressService only exposes getProgress and listActiveOperations (archon-ui-main/src/features/progress/services/progressService.ts); there are no timers or polling logic in that file. Polling/timers live in useProgressQueries (archon-ui-main/src/features/progress/hooks/useProgressQueries.ts — refetchInterval + setTimeouts).

archon-ui-main/src/features/progress/hooks/useProgressQueries.ts (1)

15-18: Keys look good and consistent.

all/lists/detail/active follow the v5 factory pattern and mirror backend routes.

archon-ui-main/src/features/knowledge/hooks/tests/useKnowledgeQueries.test.ts (1)

58-72: Key factory assertions look correct.

Tests align with the new key shapes, including summaries(filter).

Also applies to: 74-77

archon-ui-main/src/features/projects/tasks/hooks/useTaskQueries.ts (2)

21-31: Good: disabled key + enabled gate + smart polling + staleTime.

Pattern matches v5 guidance and repo rules.


101-107: Counts invalidation is correct.

Invalidating taskKeys.counts() after create/update(status)/delete keeps aggregates fresh.

Also applies to: 153-154, 197-198

archon-ui-main/src/features/projects/hooks/useProjectQueries.ts (3)

12-16: Key factory rework is consistent.

detail(id) and features(id) shapes align with the standard; tasks/docs moved out—good separation.


91-99: Verify createProject response shape.

Code assumes { project } response. If the service returns a Project directly, replace response.project with response.

Would you like me to scan the repo for createProject’s return type and patch this if needed?


108-113: Optimistic flows look solid.

Good cancel/snapshot/rollback and targeted invalidations/removals.

Also applies to: 156-166, 204-209

archon-ui-main/src/features/knowledge/hooks/useKnowledgeQueries.ts (1)

42-46: Enabled + DISABLED_QUERY_KEY pattern looks good

Good alignment with the shared pattern and stale time standardization.

Comment thread archon-ui-main/src/features/knowledge/hooks/useKnowledgeQueries.ts
Comment thread archon-ui-main/src/features/knowledge/hooks/useKnowledgeQueries.ts Outdated
Comment thread archon-ui-main/src/features/knowledge/hooks/useKnowledgeQueries.ts Outdated
Wirasm and others added 5 commits September 17, 2025 22:57
- Remove ambiguous top-level tags field from KnowledgeItem interface
- Update all UI components to use metadata.tags exclusively
- Fix mutations to correctly update tags in metadata object
- Remove duplicate tags field from backend KnowledgeSummaryService
- Fix test setup issue with QueryClient instance in knowledge tests
- Add TODO comments for filter-blind optimistic updates (Phase 3)

This eliminates the ambiguity identified in Phase 2 where both item.tags
and metadata.tags existed, establishing metadata.tags as the single
source of truth across the entire stack.
- Integrate useSmartPolling for all polling queries
- Fix memory leaks from uncleaned timeouts
- Replace string-based error checking with status codes
- Remove TypeScript any usage with proper types
- Fix unstable dependencies with sorted JSON serialization
- Add staleTime to document queries for consistency
- Changed assignee from restricted enum to flexible string type
- Renamed "AI IDE Agent" to "Coding Agent" for clarity
- Enhanced ComboBox with Radix UI best practices:
  - Full ARIA compliance (roles, labels, keyboard nav)
  - Performance optimizations (memoization, useCallback)
  - Improved UX (auto-scroll, keyboard shortcuts)
  - Fixed event bubbling preventing unintended modal opens
- Updated MCP server docs to reflect flexible assignee capability
- Removed unnecessary UI elements (arrows, helper text)
- Styled ComboBox to match priority selector aesthetic

This allows external MCP clients to create and assign custom sub-agents
dynamically, supporting advanced agent orchestration workflows.

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
- Fix all knowledgeKeys.summaries() calls to use summariesPrefix() for operations targeting multiple summary caches
- Update cancelQueries, getQueriesData, setQueriesData, invalidateQueries, and refetchQueries calls
- Fix critical cache invalidation bug where filtered summaries weren't being cleared
- Update test expectations to match new factory patterns
- Address CodeRabbit review feedback on cache stability issues

This completes the Phase 2 Query Keys Standardization work documented in PRPs/local/frontend-state-management-refactor.md

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
Update task assignee documentation from "AI IDE Agent" to "Coding Agent"
to match frontend changes for consistency across the system.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

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

⚠️ Outside diff range comments (8)
python/src/mcp_server/features/tasks/task_tools.py (3)

95-96: Percent‑encode path parameters in URLs.

Raw path segments can break routing if they contain “/”, “?” or “%”; encode IDs to avoid malformed requests and ambiguous server logs.

-from urllib.parse import urljoin
+from urllib.parse import urljoin, quote
@@
-                    response = await client.get(urljoin(api_url, f"/api/tasks/{task_id}"))
+                    response = await client.get(urljoin(api_url, f"/api/tasks/{quote(task_id, safe='')}"))
@@
-                url = urljoin(api_url, f"/api/projects/{filter_value}/tasks")
+                url = urljoin(api_url, f"/api/projects/{quote(filter_value, safe='')}/tasks")
@@
-                    response = await client.put(
-                        urljoin(api_url, f"/api/tasks/{task_id}"),
+                    response = await client.put(
+                        urljoin(api_url, f"/api/tasks/{quote(task_id, safe='')}"),
                         json=update_fields
                     )
@@
-                    response = await client.delete(
-                        urljoin(api_url, f"/api/tasks/{task_id}")
-                    )
+                    response = await client.delete(urljoin(api_url, f"/api/tasks/{quote(task_id, safe='')}"))

Also applies to: 124-125, 305-306, 334-335


126-142: Doc advertises assignee filter, but it’s not implemented.

Add an assignee branch so find_tasks(filter_by="assignee", filter_value="...") works as documented.

             elif filter_by == "status" and filter_value:
                 # Use generic tasks endpoint for status filtering
                 url = urljoin(api_url, "/api/tasks")
                 params["status"] = filter_value
                 params["include_closed"] = include_closed
                 if project_id:
                     params["project_id"] = project_id
+            elif filter_by == "assignee" and filter_value:
+                url = urljoin(api_url, "/api/tasks")
+                params["assignee"] = filter_value
+                params["include_closed"] = include_closed
+                if project_id:
+                    params["project_id"] = project_id
             elif project_id:

7-13: Add retry with exponential backoff for outbound HTTP calls.

Per backend guidelines, wrap httpx requests with limited retries and jitter; improves resilience without hiding failures.

 import json
 import logging
+import asyncio
 from typing import Any
-from urllib.parse import urljoin
+from urllib.parse import urljoin, quote
@@
 logger = logging.getLogger(__name__)
 
+# Lightweight retry helper (network/transient errors)
+async def _request(
+    client: httpx.AsyncClient,
+    method: str,
+    url: str,
+    *,
+    max_retries: int = 3,
+    **kwargs: Any,
+) -> httpx.Response:
+    last_exc: Exception | None = None
+    for attempt in range(max_retries):
+        try:
+            return await client.request(method, url, **kwargs)
+        except httpx.RequestError as e:
+            last_exc = e
+            if attempt == max_retries - 1:
+                raise
+            await asyncio.sleep(0.25 * (2 ** attempt))  # 250ms, 500ms
+    assert last_exc  # for type checkers
+    raise last_exc
+
@@
-                    response = await client.get(urljoin(api_url, f"/api/tasks/{quote(task_id, safe='')}"))
+                    response = await _request(client, "GET", urljoin(api_url, f"/api/tasks/{quote(task_id, safe='')}"))
@@
-                response = await client.get(url, params=params)
+                response = await _request(client, "GET", url, params=params)
@@
-                    response = await client.post(
-                        urljoin(api_url, "/api/tasks"),
+                    response = await _request(
+                        client,
+                        "POST",
+                        urljoin(api_url, "/api/tasks"),
                         json={
                             "project_id": project_id,
                             "title": title,
                             "description": description or "",
                             "assignee": assignee or "User",
                             "task_order": task_order or 0,
                             "feature": feature,
                             "sources": [],
                             "code_examples": [],
                         },
-                    )
+                    )
@@
-                    response = await client.put(
-                        urljoin(api_url, f"/api/tasks/{quote(task_id, safe='')}"),
+                    response = await _request(
+                        client,
+                        "PUT",
+                        urljoin(api_url, f"/api/tasks/{quote(task_id, safe='')}"),
                         json=update_fields
-                    )
+                    )
@@
-                    response = await client.delete(urljoin(api_url, f"/api/tasks/{quote(task_id, safe='')}"))
+                    response = await _request(
+                        client, "DELETE", urljoin(api_url, f"/api/tasks/{quote(task_id, safe='')}")
+                    )

Also applies to: 19-30, 94-96, 144-145, 243-246, 304-307, 333-335

archon-ui-main/src/features/projects/tasks/components/EditableTableCell.tsx (1)

154-189: Same auto‑save issue in Select branch

Replicate the await + isSaving pattern to handle errors and prevent races.

-        onValueChange={(newValue) => {
-          setEditValue(newValue);
-          // Auto-save on select
-          setTimeout(() => {
-            setEditValue(newValue);
-            onSave(newValue);
-            setIsEditing(false);
-          }, 0);
-        }}
+        onValueChange={async (newValue) => {
+          setEditValue(newValue);
+          setIsSaving(true);
+          try {
+            await onSave(newValue);
+            setIsEditing(false);
+          } catch (error) {
+            console.error("Failed to save:", error);
+            setEditValue(value);
+          } finally {
+            setIsSaving(false);
+          }
+        }}

Also consider adding isLoading={isSaving} to Select (if supported) or show a small inline spinner.

python/src/server/services/knowledge/knowledge_summary_service.py (1)

28-35: Add tags filtering to match client API (contract mismatch).

Frontend sends tags[]=... in getKnowledgeSummaries(), but the service ignores tags. Implement tags filtering for both the data and the count queries to avoid incorrect results in filtered views.

Apply:

@@
-    async def get_summaries(
+    async def get_summaries(
         self,
         page: int = 1,
         per_page: int = 20,
         knowledge_type: Optional[str] = None,
         search: Optional[str] = None,
+        tags: Optional[list[str]] = None,
     ) -> dict[str, Any]:
@@
-            # Apply filters
+            # Apply filters
             if knowledge_type:
                 query = query.contains("metadata", {"knowledge_type": knowledge_type})
 
             if search:
                 search_pattern = f"%{search}%"
                 query = query.or_(
                     f"title.ilike.{search_pattern},summary.ilike.{search_pattern}"
                 )
+            if tags:
+                # Require item to contain all requested tags
+                query = query.contains("metadata", {"tags": tags})
@@
-            if knowledge_type:
+            if knowledge_type:
                 count_query = count_query.contains("metadata", {"knowledge_type": knowledge_type})
 
             if search:
                 search_pattern = f"%{search}%"
                 count_query = count_query.or_(
                     f"title.ilike.{search_pattern},summary.ilike.{search_pattern}"
                 )
+            if tags:
+                count_query = count_query.contains("metadata", {"tags": tags})

Also applies to: 60-83, 71-83

archon-ui-main/src/features/knowledge/services/knowledgeService.ts (2)

31-39: Client sends tags param but server ignores it; align or remove for now.

Until the server supports tags filtering, remove tags from the query to avoid misleading expectations.

-    if (filter?.tags?.length) {
-      for (const tag of filter.tags) {
-        params.append("tags", tag);
-      }
-    }
+    // TODO: Re-enable when backend supports tags filtering on summaries
+    // if (filter?.tags?.length) for (const tag of filter.tags) params.append("tags", tag);

68-75: Map top-level tags into metadata before sending PUT

Server stores tags under metadata (update_knowledge_item manipulates metadata; services read metadata.get("tags", [])). Convert updates.tags → metadata.tags before sending the request.

   async updateKnowledgeItem(
     sourceId: string,
     updates: Partial<KnowledgeItem> & { tags?: string[] },
   ): Promise<KnowledgeItem> {
-    const response = await callAPIWithETag<KnowledgeItem>(`/api/knowledge-items/${sourceId}`, {
+    const body: any = { ...updates };
+    if ("tags" in body) {
+      body.metadata = { ...(body.metadata ?? {}), tags: body.tags };
+      delete body.tags;
+    }
+    const response = await callAPIWithETag<KnowledgeItem>(`/api/knowledge-items/${sourceId}`, {
       method: "PUT",
-      body: JSON.stringify(updates),
+      body: JSON.stringify(body),
     });
archon-ui-main/src/features/knowledge/hooks/useKnowledgeQueries.ts (1)

205-218: Write optimistic operations to progressKeys.active(), not lists().

Active operations consumers use the active() key; writing to lists() makes optimistic updates invisible.

-      queryClient.setQueryData<ActiveOperationsResponse>(progressKeys.lists(), (old) => {
+      queryClient.setQueryData<ActiveOperationsResponse>(progressKeys.active(), (old) => {
@@
-        queryClient.setQueryData<ActiveOperationsResponse>(progressKeys.lists(), (old) => {
+        queryClient.setQueryData<ActiveOperationsResponse>(progressKeys.active(), (old) => {
@@
-      queryClient.cancelQueries({ queryKey: progressKeys.lists() });
+      queryClient.cancelQueries({ queryKey: progressKeys.active() });
@@
-      const previousOperations = queryClient.getQueryData<ActiveOperationsResponse>(progressKeys.lists());
+      const previousOperations = queryClient.getQueryData<ActiveOperationsResponse>(progressKeys.active());
@@
-      queryClient.setQueryData<ActiveOperationsResponse>(progressKeys.lists(), (old) => {
+      queryClient.setQueryData<ActiveOperationsResponse>(progressKeys.active(), (old) => {
@@
-        queryClient.setQueryData<ActiveOperationsResponse>(progressKeys.lists(), (old) => {
+        queryClient.setQueryData<ActiveOperationsResponse>(progressKeys.active(), (old) => {
@@
-        queryClient.invalidateQueries({ queryKey: progressKeys.lists() });
+        queryClient.invalidateQueries({ queryKey: progressKeys.active() });
@@
-        queryClient.setQueryData(progressKeys.lists(), context.previousOperations);
+        queryClient.setQueryData(progressKeys.active(), context.previousOperations);

Also applies to: 260-277, 333-340, 405-418, 443-460, 465-468, 481-482

🧹 Nitpick comments (40)
python/src/mcp_server/features/tasks/task_tools.py (4)

215-219: Docstring update aligns with runtime; add one-line clarity.

Clarify that updates preserve the existing assignee when omitted; minor polish only.

-                     Default: "User"
+                     Default: "User". On update, if omitted, the assignee remains unchanged.

224-225: Examples are solid; add default-assignee example.

Helps readers see implicit "User".

         Examples:
           manage_task("create", project_id="p-1", title="Fix auth bug", assignee="CodeAnalyzer-v2")
           manage_task("update", task_id="t-1", status="doing", assignee="User")
+          manage_task("create", project_id="p-1", title="Write docs")  # assignee defaults to "User"
           manage_task("delete", task_id="t-1")

257-273: Treat all 2xx as success; handle 201/204 bodies safely.

Avoid false negatives on APIs returning 201/204 or empty bodies.

-                    if response.status_code == 200:
+                    if response.is_success:
                         result = response.json()
                         task = result.get("task")
@@
-                    if response.status_code == 200:
-                        result = response.json()
-                        task = result.get("task")
+                    if response.is_success:
+                        if response.status_code == 204 or not response.content:
+                            return json.dumps({"success": True, "task": None, "message": "Task updated successfully"})
+                        result = response.json()
+                        task = result.get("task")
@@
-                    if response.status_code == 200:
-                        result = response.json()
-                        return json.dumps({
-                            "success": True,
-                            "message": result.get("message", "Task deleted successfully"),
-                        })
+                    if response.is_success:
+                        if response.status_code == 204 or not response.content:
+                            return json.dumps({"success": True, "message": "Task deleted successfully"})
+                        result = response.json()
+                        return json.dumps({"success": True, "message": result.get("message", "Task deleted successfully")})

Also applies to: 309-324, 337-343


21-24: Clamp pagination to prevent abuse; add max page size.

Limit per_page and page to sane bounds to avoid expensive queries.

 # Optimization constants
 MAX_DESCRIPTION_LENGTH = 1000
-DEFAULT_PAGE_SIZE = 10  # Reduced from 50
+DEFAULT_PAGE_SIZE = 10  # Reduced from 50
+MAX_PAGE_SIZE = 100
@@
-        per_page: int = DEFAULT_PAGE_SIZE,  # Use optimized default
+        per_page: int = DEFAULT_PAGE_SIZE,  # Use optimized default
@@
-            params: dict[str, Any] = {
+            # sanitize pagination
+            page = max(1, page)
+            per_page = max(1, min(per_page, MAX_PAGE_SIZE))
+            params: dict[str, Any] = {
                 "page": page,
                 "per_page": per_page,
                 "exclude_large_fields": True,  # Always exclude large fields in MCP responses
             }

Also applies to: 63-65, 112-116

archon-ui-main/src/features/progress/hooks/useProgressQueries.ts (7)

41-41: Background polling interval likely too slow vs guidelines

useSmartPolling currently uses 60s when window is visible but unfocused; guidelines say 5–10s. Recommend adjusting globally.

Proposed change in useSmartPolling:

--- a/archon-ui-main/src/features/ui/hooks/useSmartPolling.ts
+++ b/archon-ui-main/src/features/ui/hooks/useSmartPolling.ts
@@
-    if (!hasFocus) {
-      // Page is visible but not focused - poll less frequently (1 minute)
-      return 60000; // 60 seconds for background polling
-    }
+    if (!hasFocus) {
+      // Page is visible but not focused - poll less frequently (10 seconds)
+      return 10000; // Align with 5–10s background guidance
+    }

60-76: Deduplicate and tighten 404 detection

The “not found” heuristic is duplicated and broad. Extract a shared helper (and consider 410 Gone) to avoid drift.

Example helper:

// src/features/shared/http.ts
export function isNotFoundLike(error: unknown): boolean {
  return (
    (error instanceof APIServiceError && error.statusCode === 404) ||
    (error as { status?: number })?.status === 404 ||
    (error as { response?: { status?: number } })?.response?.status === 404 ||
    (error as { status?: number })?.status === 410 ||
    (error instanceof Error && /\b(not\s*found|404|gone|410)\b/i.test(error.message))
  );
}

Usage here: const isNotFound = isNotFoundLike(error);

Also applies to: 267-274


113-118: Scope query removals to exact keys

Add exact: true to avoid accidentally removing sibling queries under the same prefix.

Apply:

- queryClient.removeQueries({ queryKey: progressKeys.detail(progressId) });
+ queryClient.removeQueries({ queryKey: progressKeys.detail(progressId), exact: true });

Also applies to: 128-133, 143-148, 168-173, 325-329, 339-342, 367-369


213-220: Consider delegating to useActiveOperations to remove duplication

useCrawlProgressPolling reimplements the same query; delegate and shape the return.

 export function useCrawlProgressPolling() {
-  const { refetchInterval } = useSmartPolling(5000);
-
-  const { data, isLoading } = useQuery({
-    queryKey: progressKeys.lists(),
-    queryFn: () => progressService.listActiveOperations(),
-    refetchInterval, // Smart polling that pauses when hidden
-    staleTime: STALE_TIMES.instant, // Always fresh for active progress
-  });
+  const q = useActiveOperations(true);
+  const { data, isLoading } = q;

   const activeOperations = data?.operations || [];

251-256: Stabilize dependency without recomputing JSON each render

Minor: memoize the sorted key to avoid redundant stringification on every render.

// Add: import { useMemo } from "react";
const idsKey = useMemo(() => JSON.stringify([...progressIds].sort()), [progressIds]);
useEffect(() => {
  completedIds.current.clear();
  errorIds.current.clear();
  notFoundCounts.current.clear();
}, [idsKey]);

259-260: Avoid unnecessary cast on queryKey

progressKeys.detail(progressId) is readonly string[] already assignable to QueryKey. Drop the cast if TS allows.

Try:

-      queryKey: progressKeys.detail(progressId) as readonly unknown[],
+      queryKey: progressKeys.detail(progressId),

289-303: Typed refetchInterval param (optional)

You can type the param to match TanStack’s RefetchIntervalFunction for clarity, but inference is fine.

refetchInterval: (query: { state: { data: ProgressResponse | null | undefined } }) => { ... }
archon-ui-main/src/features/projects/tasks/hooks/useTaskQueries.ts (5)

8-15: Key factory aligns with backend routes; minor naming nit.

The key shapes look correct and mirror the API. Consider aligning method/segment plurality for consistency (e.g., list() -> "list" or lists() -> "lists"). Also note that byProject is rooted under ["projects", ...] rather than ["tasks", ...]; ensure docs/tests don’t rely on invalidating taskKeys.all to cover per‑project caches.


19-19: Poll interval deviates from our guideline (1–2s active).

Recommend 2s active to match the coding guideline; background can remain smart‑paused by useSmartPolling.

-  const { refetchInterval } = useSmartPolling(5000); // 5 second base interval for faster MCP updates
+  const { refetchInterval } = useSmartPolling(2000); // 2s active per guideline

53-57: Type the snapshot for safer rollbacks.

getQueryData without a generic returns unknown; add Task[] for type‑safety.

-      const previousTasks = queryClient.getQueryData(taskKeys.byProject(newTaskData.project_id));
+      const previousTasks = queryClient.getQueryData<Task[]>(
+        taskKeys.byProject(newTaskData.project_id),
+      );

121-127: Tighten counts invalidation on update errors.

On error, invalidate counts only if status was optimistically changed, mirroring onSuccess behavior.

-      queryClient.invalidateQueries({ queryKey: taskKeys.counts() });
+      if (variables.updates?.status) {
+        queryClient.invalidateQueries({ queryKey: taskKeys.counts() });
+      }

Also applies to: 143-145, 148-154


170-176: After delete, also refetch the project’s task list.

Optimistic removal is fine, but a list refetch helps reconcile server‑side ordering or cross‑effects.

     onSettled: () => {
       // Always refetch counts after deletion
       queryClient.invalidateQueries({ queryKey: taskKeys.counts() });
+      queryClient.invalidateQueries({ queryKey: taskKeys.byProject(projectId) });
     },

Also applies to: 197-198

archon-ui-main/src/features/projects/tasks/types/task.ts (2)

17-19: Common assignees exported: align naming across UI copy.

Constant looks fine. Ensure UI descriptions and any docs consistently say “Coding Agent” (not “AI IDE Agent”) to avoid user-facing inconsistencies.


14-16: Assignee widened to string — backend/DB verified; update docs/OpenAPI if present.

DB migration and server-side validation accept arbitrary non-empty strings; frontend schema enforces string length. Quick pointers:

  • migration/complete_setup.sql — assignee is TEXT DEFAULT 'User' with CHECK (assignee IS NOT NULL AND assignee != '').
  • migration/RESET_DB.sql — drops previous task_assignee type.
  • python/src/server/services/projects/task_service.py — validate_assignee requires a non-empty string.
  • archon-ui-main/src/features/projects/tasks/schemas/index.ts — AssigneeSchema is z.string().min(1).max(100).
  • PRPs/ai_docs/API_NAMING_CONVENTIONS.md (and some docs) still list Assignee as a fixed union — update docs/OpenAPI contract if you maintain one.
archon-ui-main/src/features/ui/primitives/combobox.tsx (4)

173-183: A11y: move combobox semantics off the trigger button.

Current roles/aria on the Button don’t reflect the interactive element used for typing. Prefer putting role/aria on the text input and keeping the button a plain trigger.

-          <Button
+          <Button
             ref={ref}
-            variant="ghost"
-            role="combobox"
-            aria-expanded={open}
-            aria-haspopup="listbox"
-            aria-controls={open ? listboxId : undefined}
-            aria-label={ariaLabel}
-            aria-labelledby={ariaLabelledBy}
-            aria-describedby={ariaDescribedBy}
+            variant="ghost"
             disabled={disabled || isLoading}
             onClick={(e) => e.stopPropagation()}
             onKeyDown={(e) => {
               // Stop propagation to prevent parent handlers
               e.stopPropagation();
               // Allow Space to open the dropdown
               if (e.key === " ") {
                 e.preventDefault();
                 setOpen(true);
               }
+              // Also open on Enter/ArrowDown for better keyboard UX
+              if (e.key === "Enter" || e.key === "ArrowDown") {
+                e.preventDefault();
+                setOpen(true);
+              }
             }}

239-247: A11y: put combobox roles on the input and expose activedescendant.

Give the input role="combobox", aria-expanded, aria-controls, and aria-activedescendant to announce the highlighted option to AT.

               <input
                 ref={inputRef}
                 type="text"
-                role="searchbox"
-                aria-label="Search options"
-                aria-controls={listboxId}
-                aria-autocomplete="list"
+                role="combobox"
+                aria-label={ariaLabel ?? "Search options"}
+                aria-labelledby={ariaLabelledBy}
+                aria-describedby={ariaDescribedBy}
+                aria-controls={listboxId}
+                aria-expanded={open}
+                aria-autocomplete="list"
+                aria-activedescendant={
+                  open
+                    ? (hasCustomOption && highlightedIndex === filteredOptions.length
+                        ? `${listboxId}-custom`
+                        : `${listboxId}-opt-${highlightedIndex}`)
+                    : undefined
+                }

293-327: A11y: give options stable ids for aria-activedescendant targeting.

Add id to each option; keep role/aria-selected as-is.

-                        <button
+                        <button
                           type="button"
                           key={option.value}
                           role="option"
+                          id={`${listboxId}-opt-${index}`}
                           aria-selected={isSelected}
                           data-highlighted={isHighlighted}

330-349: A11y + styling nit: id for custom option and invalid Tailwind class.

Add id for the custom option and replace unsupported ml-4.5 with ml-4.

-                      <button
+                      <button
                         type="button"
                         role="option"
+                        id={`${listboxId}-custom`}
                         aria-selected={false}
                         data-highlighted={highlightedIndex === filteredOptions.length}
                         onClick={handleCustomValue}
                         onMouseEnter={() => setHighlightedIndex(filteredOptions.length)}
...
-                        <span className="ml-4.5">Add "{search}"</span>
+                        <span className="ml-4">Add "{search}"</span>
archon-ui-main/src/features/projects/tasks/schemas/index.ts (1)

7-11: Trim and validate whitespace-only assignees.

Add .trim() so inputs like " " don’t pass .min(1) and to persist a normalized value.

-export const AssigneeSchema = z
-  .string()
-  .min(1, "Assignee cannot be empty")
-  .max(100, "Assignee name must be less than 100 characters");
+export const AssigneeSchema = z
+  .string()
+  .trim()
+  .min(1, "Assignee cannot be empty")
+  .max(100, "Assignee name must be less than 100 characters");
archon-ui-main/src/features/projects/tasks/components/TaskEditModal.tsx (4)

35-41: Copy mismatch: description says “AI IDE Agent” while option is “Coding Agent”.

Align the description with the visible option to avoid confusion.

 const ASSIGNEE_OPTIONS: ComboBoxOption[] = COMMON_ASSIGNEES.map((name) => ({
   value: name,
   label: name,
-  description:
-    name === "User" ? "Assign to human user" : name === "Archon" ? "Assign to Archon system" : "Assign to AI IDE Agent",
+  description:
+    name === "User"
+      ? "Assign to human user"
+      : name === "Archon"
+        ? "Assign to Archon system"
+        : "Assign to Coding Agent",
 }));

60-63: Unnecessary cast.

Assignee is now a plain string; drop the redundant type assertion.

-          assignee: "User" as Assignee,
+          assignee: "User",

161-174: A11y: associate the Label with the ComboBox trigger via aria-labelledby.

Give the Label an id and pass it down so the control has an accessible name.

-              <FormField>
-                <Label>Assignee</Label>
+              <FormField>
+                <Label id="assignee-label">Assignee</Label>
                 <ComboBox
                   options={ASSIGNEE_OPTIONS}
                   value={localTask?.assignee || "User"}
                   onValueChange={(value) => setLocalTask((prev) => (prev ? { ...prev, assignee: value } : null))}
                   placeholder="Select or type assignee..."
                   searchPlaceholder="Search or enter custom..."
                   emptyMessage="Type a custom assignee name"
                   className="w-full"
                   allowCustomValue={true}
+                  aria-labelledby="assignee-label"
                 />

35-41: Optional: surface option descriptions in the ComboBox list.

You’re computing descriptions but the ComboBox only renders labels. Either render descriptions (secondary text) or drop them to reduce noise.

Also applies to: 161-174

archon-ui-main/src/features/projects/tasks/components/EditableTableCell.tsx (2)

3-12: Import path consistency with TaskAssignee

This file uses the primitives barrel; TaskAssignee imports ComboBox from the specific module. Pick one style (prefer the barrel) and standardize.


122-125: Truncation length inconsistent with TaskAssignee

This truncates at 20 chars; TaskAssignee uses 25. Unify to avoid janky table vs. card widths. Minimal tweak below.

-  {type === "assignee" && value && value.length > 20 ? `${value.slice(0, 17)}...` : value || placeholder}
+  {type === "assignee" && value && value.length > 25 ? `${value.slice(0, 22)}...` : value || placeholder}

Optionally extract a shared truncateAssignee(name, max=25) helper.

archon-ui-main/src/features/projects/tasks/components/TaskAssignee.tsx (5)

3-3: Unify import style for primitives

Import ComboBox from the primitives barrel (matches EditableTableCell) to keep imports consistent.

-import { ComboBox, type ComboBoxOption } from "../../../ui/primitives/combobox";
+import { ComboBox, type ComboBoxOption } from "../../../ui/primitives";

19-23: Centralize truncation helper

This file truncates at 25 chars; EditableTableCell used 20. Recommend a shared truncateAssignee(name, max=25) in tasks/utils and reuse in both places.


26-51: Duplicate getAssigneeIcon logic — use shared util

There’s an existing getAssigneeIcon in tasks/utils/task-styles.tsx with different rules. Consolidate to a single source and extend the util to support AI/agent heuristics and the fallback initial overlay.

Proposed update to utils (outside this file):

// features/projects/tasks/utils/task-styles.tsx
import { Bot, User } from "lucide-react";

export const getAssigneeIcon = (assigneeName: string, size: "sm" | "md" = "sm") => {
  const sizeClass = size === "sm" ? "w-3 h-3" : "w-4 h-4";
  if (assigneeName === "User") return <User className={`${sizeClass} text-blue-400`} />;
  if (assigneeName === "Archon") return <img src="/logo-neon.png" alt="Archon" className={sizeClass} />;
  if (
    assigneeName === "Coding Agent" ||
    assigneeName.toLowerCase().includes("agent") ||
    assigneeName.toLowerCase().includes("ai")
  ) {
    return <Bot className={`${sizeClass} text-purple-400`} />;
  }
  return (
    <div className="relative flex items-center justify-center">
      <Bot className={`${sizeClass} text-gray-400 opacity-60`} />
      <span className="absolute text-[8px] font-bold text-white/90">{assigneeName[0]?.toUpperCase() || "?"}</span>
    </div>
  );
};

Then import it here and remove the local function.

-const getAssigneeIcon = (assigneeName: string, size: "sm" | "md" = "sm") => {
-  ...
-};
+import { getAssigneeIcon } from "../utils/task-styles";

53-88: Consider moving style resolver to utils

getAssigneeStyles is a good candidate for tasks/utils/task-styles.tsx to keep icon/colors consistent across surfaces.


117-136: Minor a11y and loading polish for ComboBox

  • Provide an aria-label for screen readers.
  • Pass isLoading to show the built-in loading affordance.
-      <ComboBox
+      <ComboBox
         options={ASSIGNEE_OPTIONS}
         value={assignee}
         onValueChange={onAssigneeChange}
         placeholder="Assignee"
         searchPlaceholder="Assign to..."
         emptyMessage="Press Enter to add"
         className="min-w-[90px] max-w-[140px]"
         allowCustomValue={true}
-        disabled={isLoading}
+        disabled={isLoading}
+        isLoading={isLoading}
+        aria-label="Change assignee"
       />
python/src/server/services/knowledge/knowledge_summary_service.py (2)

44-51: Validate pagination inputs (defensive defaults).

Guard against page < 1 and per_page <= 0 to prevent negative ranges.

@@
-            page: Page number (1-based)
+            page: Page number (1-based; <=0 coerced to 1)
@@
-            # Apply pagination
-            start_idx = (page - 1) * per_page
+            # Apply pagination (defensive)
+            page = max(1, page or 1)
+            per_page = max(1, per_page or 20)
+            start_idx = (page - 1) * per_page

Also applies to: 87-91


178-191: Avoid N+1 count queries; batch with a single GROUP BY.

Both _get_document_counts_batch and _get_code_example_counts_batch loop per source. Replace with one query each to reduce load.

I can provide a Supabase SQL RPC or a single select with group by if you confirm table/index names. Do you want me to draft that?

Also applies to: 211-219

archon-ui-main/src/features/knowledge/hooks/tests/useKnowledgeQueries.test.ts (2)

129-145: Seed summaries cache, not lists(), for delete mutation tests.

The mutation optimizes against summaries caches; pre-populate those to make the test representative.

-  // Pre-populate cache with the same client instance
-  queryClient.setQueryData(knowledgeKeys.lists(), initialData);
+  // Pre-populate summaries (no filter) with the same client instance
+  queryClient.setQueryData(knowledgeKeys.summaries(undefined), initialData);

Also applies to: 137-143


86-101: Consider asserting cache effects, not just mutation success.

Add expectations that the deleted item is removed from summaries.items and total decremented.

If you want, I can add a test snippet that reads queryClient.getQueryData(knowledgeKeys.summaries(undefined)).

Also applies to: 118-121

archon-ui-main/src/features/knowledge/hooks/useKnowledgeQueries.ts (2)

169-188: Make optimistic summaries updates filter-aware (avoid polluting filtered caches).

Current TODO notes this. Iterate known summaries caches and only insert when the cache’s filter matches (knowledge_type/tags).

I can provide a small helper that inspects the third element of each knowledgeKeys.summaries(filter) key and applies predicate checks before setQueryData.

Also applies to: 373-389


84-91: Consolidate duplicate hooks (useCodeExamples vs useKnowledgeCodeExamples).

Two code-examples hooks increase API surface and can diverge. Deprecate the simple one or forward to the typed version.

-export function useCodeExamples(sourceId: string | null) {
+/** @deprecated Use useKnowledgeCodeExamples with options instead. */
+export function useCodeExamples(sourceId: string | null) {

Or remove if unused.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3c902ae and 80fc64e.

📒 Files selected for processing (21)
  • archon-ui-main/src/features/knowledge/components/KnowledgeCard.tsx (3 hunks)
  • archon-ui-main/src/features/knowledge/components/KnowledgeList.tsx (1 hunks)
  • archon-ui-main/src/features/knowledge/hooks/tests/useKnowledgeQueries.test.ts (2 hunks)
  • archon-ui-main/src/features/knowledge/hooks/useKnowledgeQueries.ts (31 hunks)
  • archon-ui-main/src/features/knowledge/services/knowledgeService.ts (1 hunks)
  • archon-ui-main/src/features/knowledge/views/KnowledgeView.tsx (1 hunks)
  • archon-ui-main/src/features/progress/components/CrawlingProgress.tsx (1 hunks)
  • archon-ui-main/src/features/progress/hooks/tests/useProgressQueries.test.ts (1 hunks)
  • archon-ui-main/src/features/progress/hooks/useProgressQueries.ts (16 hunks)
  • archon-ui-main/src/features/projects/documents/hooks/useDocumentQueries.ts (2 hunks)
  • archon-ui-main/src/features/projects/hooks/useProjectQueries.ts (2 hunks)
  • archon-ui-main/src/features/projects/tasks/components/EditableTableCell.tsx (4 hunks)
  • archon-ui-main/src/features/projects/tasks/components/TaskAssignee.tsx (2 hunks)
  • archon-ui-main/src/features/projects/tasks/components/TaskEditModal.tsx (4 hunks)
  • archon-ui-main/src/features/projects/tasks/hooks/useTaskQueries.ts (10 hunks)
  • archon-ui-main/src/features/projects/tasks/schemas/index.ts (1 hunks)
  • archon-ui-main/src/features/projects/tasks/types/index.ts (2 hunks)
  • archon-ui-main/src/features/projects/tasks/types/task.ts (4 hunks)
  • archon-ui-main/src/features/ui/primitives/combobox.tsx (3 hunks)
  • python/src/mcp_server/features/tasks/task_tools.py (1 hunks)
  • python/src/server/services/knowledge/knowledge_summary_service.py (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (7)
  • archon-ui-main/src/features/progress/components/CrawlingProgress.tsx
  • archon-ui-main/src/features/knowledge/components/KnowledgeList.tsx
  • archon-ui-main/src/features/progress/hooks/tests/useProgressQueries.test.ts
  • archon-ui-main/src/features/knowledge/components/KnowledgeCard.tsx
  • archon-ui-main/src/features/projects/hooks/useProjectQueries.ts
  • archon-ui-main/src/features/knowledge/views/KnowledgeView.tsx
  • archon-ui-main/src/features/projects/documents/hooks/useDocumentQueries.ts
🧰 Additional context used
📓 Path-based instructions (10)
archon-ui-main/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

archon-ui-main/src/**/*.{ts,tsx}: Use TanStack Query for all data fetching; avoid prop drilling
TypeScript: strict mode with no implicit any in frontend code
State naming: is[Action]ing for loading flags, [resource]Error for errors, selected[Resource] for current selection
Use HTTP polling with ETag caching; do not introduce WebSocket-based updates in the frontend

archon-ui-main/src/**/*.{ts,tsx}: WebSocket event failures (if any) should be logged and not crash the client; continue serving others
Frontend data fetching must use TanStack Query (no prop drilling) with query key factories, smart polling, and optimistic updates with rollback
Use vertical slice architecture: place UI under src/features/[feature]/(components|hooks|services|types)
State naming: use is[Action]ing for loading, [resource]Error for errors, selected[Resource] for selections
Service method names: get[Resource]sByProject(projectId), getResource, create/update/delete patterns
Frontend TypeScript should be strict (no implicit any)

Files:

  • archon-ui-main/src/features/projects/tasks/types/index.ts
  • archon-ui-main/src/features/knowledge/services/knowledgeService.ts
  • archon-ui-main/src/features/projects/tasks/types/task.ts
  • archon-ui-main/src/features/projects/tasks/schemas/index.ts
  • archon-ui-main/src/features/projects/tasks/components/TaskAssignee.tsx
  • archon-ui-main/src/features/projects/tasks/components/EditableTableCell.tsx
  • archon-ui-main/src/features/projects/tasks/components/TaskEditModal.tsx
  • archon-ui-main/src/features/ui/primitives/combobox.tsx
  • archon-ui-main/src/features/projects/tasks/hooks/useTaskQueries.ts
  • archon-ui-main/src/features/knowledge/hooks/useKnowledgeQueries.ts
  • archon-ui-main/src/features/progress/hooks/useProgressQueries.ts
  • archon-ui-main/src/features/knowledge/hooks/tests/useKnowledgeQueries.test.ts
archon-ui-main/src/features/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

archon-ui-main/src/features/**/*.{ts,tsx}: Follow TanStack Query patterns: query-keys factory, smart polling via useSmartPolling, optimistic updates with rollback
Biome formatting in features: 120-character lines, double quotes, trailing commas

archon-ui-main/src/features/**/*.{ts,tsx}: Use Biome formatting/conventions in /src/features: 120-char lines, double quotes, trailing commas
Use useSmartPolling and polling intervals (1–2s active, 5–10s background) with smart pausing on tab inactivity
Expose progress via dedicated hooks (e.g., useCrawlProgressPolling, useProjectTasks) instead of ad-hoc timers
Do not use prop drilling for data fetching/state; rely on TanStack Query caches/selectors

Files:

  • archon-ui-main/src/features/projects/tasks/types/index.ts
  • archon-ui-main/src/features/knowledge/services/knowledgeService.ts
  • archon-ui-main/src/features/projects/tasks/types/task.ts
  • archon-ui-main/src/features/projects/tasks/schemas/index.ts
  • archon-ui-main/src/features/projects/tasks/components/TaskAssignee.tsx
  • archon-ui-main/src/features/projects/tasks/components/EditableTableCell.tsx
  • archon-ui-main/src/features/projects/tasks/components/TaskEditModal.tsx
  • archon-ui-main/src/features/ui/primitives/combobox.tsx
  • archon-ui-main/src/features/projects/tasks/hooks/useTaskQueries.ts
  • archon-ui-main/src/features/knowledge/hooks/useKnowledgeQueries.ts
  • archon-ui-main/src/features/progress/hooks/useProgressQueries.ts
  • archon-ui-main/src/features/knowledge/hooks/tests/useKnowledgeQueries.test.ts
**/*.{py,ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Never return None/null to indicate failure; raise an exception with details instead

Files:

  • archon-ui-main/src/features/projects/tasks/types/index.ts
  • python/src/server/services/knowledge/knowledge_summary_service.py
  • archon-ui-main/src/features/knowledge/services/knowledgeService.ts
  • python/src/mcp_server/features/tasks/task_tools.py
  • archon-ui-main/src/features/projects/tasks/types/task.ts
  • archon-ui-main/src/features/projects/tasks/schemas/index.ts
  • archon-ui-main/src/features/projects/tasks/components/TaskAssignee.tsx
  • archon-ui-main/src/features/projects/tasks/components/EditableTableCell.tsx
  • archon-ui-main/src/features/projects/tasks/components/TaskEditModal.tsx
  • archon-ui-main/src/features/ui/primitives/combobox.tsx
  • archon-ui-main/src/features/projects/tasks/hooks/useTaskQueries.ts
  • archon-ui-main/src/features/knowledge/hooks/useKnowledgeQueries.ts
  • archon-ui-main/src/features/progress/hooks/useProgressQueries.ts
  • archon-ui-main/src/features/knowledge/hooks/tests/useKnowledgeQueries.test.ts
python/src/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

python/src/**/*.py: Fail fast on critical conditions: service startup failures, missing configuration/env vars, database connection/auth failures, critical dependencies unavailable
Never accept or store corrupted data (e.g., zero embeddings, null foreign keys, malformed JSON); skip failed items entirely and continue processing
For batch/background operations, continue processing but log detailed per-item failures; for external APIs use retries with exponential backoff and then fail clearly
Error messages must include context, use specific exception types, preserve full stack traces (logging with exc_info=True), include relevant IDs/URLs, and never return None to indicate failure—raise instead; for batch ops report success counts and detailed failures
Backend uses Python 3.12 with a 120-character line length
Avoid introducing WebSocket support in the backend; updates are handled via HTTP polling
Adhere to Ruff lint rules (e.g., no unused imports) and provide type hints to satisfy MyPy

python/src/**/*.py: Fail fast on service startup failures (credentials, DB, service init); crash with clear errors
Treat missing configuration (env vars/invalid settings) as fatal; stop the system
Do not hide database connection failures; bubble up and surface clearly
Authentication/authorization failures must halt the operation and be visible
Never silently accept bad data; let Pydantic validation errors raise
If critical dependencies are unavailable, fail immediately
Reject invalid data that could corrupt state (e.g., zero embeddings, null FKs, malformed JSON)
Batch processing should complete remaining items but log detailed per-item failures
Background tasks (e.g., embedding generation) should finish queues while logging failures
Treat optional features as skippable: log and skip when disabled rather than crashing
External API calls: use retry with exponential backoff; on final failure, raise with clear service/context info
Never accept corrupted data during partial-failure work...

Files:

  • python/src/server/services/knowledge/knowledge_summary_service.py
  • python/src/mcp_server/features/tasks/task_tools.py
python/src/server/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Use specific exception classes and FastAPI exception handlers to produce rich JSON error responses

python/src/server/**/*.py: Provide rich error responses in FastAPI (custom exceptions and handlers that return structured JSON with detail/type)
Implement HTTP polling support and ETag caching on endpoints to enable 304 responses

Files:

  • python/src/server/services/knowledge/knowledge_summary_service.py
python/src/server/{api_routes,services}/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Follow Service Layer pattern: API routes delegate to services, which handle business logic and call the database layer

Files:

  • python/src/server/services/knowledge/knowledge_summary_service.py
python/src/server/services/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

Place business logic in service layer under python/src/server/services/

Files:

  • python/src/server/services/knowledge/knowledge_summary_service.py
archon-ui-main/src/features/**/services/**/*.ts

📄 CodeRabbit inference engine (AGENTS.md)

Frontend service method naming: get[Resource]sByProject(projectId), getResource, createResource, update[Resource](id, updates), deleteResource

Files:

  • archon-ui-main/src/features/knowledge/services/knowledgeService.ts
python/src/mcp_server/features/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

Place MCP tools under python/src/mcp_server/features/[feature]/ named find_[resource] and manage_[resource] patterns

Files:

  • python/src/mcp_server/features/tasks/task_tools.py
archon-ui-main/src/**/*.{test,spec}.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Write frontend tests with Vitest and React Testing Library

Files:

  • archon-ui-main/src/features/knowledge/hooks/tests/useKnowledgeQueries.test.ts
🧠 Learnings (8)
📓 Common learnings
Learnt from: CR
PR: coleam00/Archon#0
File: AGENTS.md:0-0
Timestamp: 2025-09-12T13:47:04.545Z
Learning: Applies to archon-ui-main/src/features/**/*.{ts,tsx} : Follow TanStack Query patterns: query-keys factory, smart polling via useSmartPolling, optimistic updates with rollback
Learnt from: CR
PR: coleam00/Archon#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-13T15:53:40.757Z
Learning: Applies to archon-ui-main/src/**/*.{ts,tsx} : Frontend data fetching must use TanStack Query (no prop drilling) with query key factories, smart polling, and optimistic updates with rollback
Learnt from: CR
PR: coleam00/Archon#0
File: AGENTS.md:0-0
Timestamp: 2025-09-12T13:47:04.545Z
Learning: Applies to archon-ui-main/src/**/*.{ts,tsx} : Use TanStack Query for all data fetching; avoid prop drilling
📚 Learning: 2025-09-13T15:53:40.757Z
Learnt from: CR
PR: coleam00/Archon#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-13T15:53:40.757Z
Learning: Applies to archon-ui-main/src/features/**/*.{ts,tsx} : Expose progress via dedicated hooks (e.g., useCrawlProgressPolling, useProjectTasks) instead of ad-hoc timers

Applied to files:

  • archon-ui-main/src/features/projects/tasks/types/index.ts
  • archon-ui-main/src/features/projects/tasks/hooks/useTaskQueries.ts
  • archon-ui-main/src/features/knowledge/hooks/useKnowledgeQueries.ts
  • archon-ui-main/src/features/progress/hooks/useProgressQueries.ts
📚 Learning: 2025-09-12T13:47:04.545Z
Learnt from: CR
PR: coleam00/Archon#0
File: AGENTS.md:0-0
Timestamp: 2025-09-12T13:47:04.545Z
Learning: Applies to archon-ui-main/src/features/**/*.{ts,tsx} : Follow TanStack Query patterns: query-keys factory, smart polling via useSmartPolling, optimistic updates with rollback

Applied to files:

  • archon-ui-main/src/features/projects/tasks/hooks/useTaskQueries.ts
  • archon-ui-main/src/features/knowledge/hooks/useKnowledgeQueries.ts
  • archon-ui-main/src/features/progress/hooks/useProgressQueries.ts
  • archon-ui-main/src/features/knowledge/hooks/tests/useKnowledgeQueries.test.ts
📚 Learning: 2025-09-13T15:53:40.757Z
Learnt from: CR
PR: coleam00/Archon#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-13T15:53:40.757Z
Learning: Applies to archon-ui-main/src/**/*.{ts,tsx} : Frontend data fetching must use TanStack Query (no prop drilling) with query key factories, smart polling, and optimistic updates with rollback

Applied to files:

  • archon-ui-main/src/features/projects/tasks/hooks/useTaskQueries.ts
  • archon-ui-main/src/features/knowledge/hooks/useKnowledgeQueries.ts
  • archon-ui-main/src/features/progress/hooks/useProgressQueries.ts
📚 Learning: 2025-08-28T13:07:24.810Z
Learnt from: Wirasm
PR: coleam00/Archon#514
File: archon-ui-main/src/services/crawlProgressService.ts:35-39
Timestamp: 2025-08-28T13:07:24.810Z
Learning: The crawlProgressService.ts in the Archon codebase should be deprecated in favor of the existing useCrawlProgressPolling hook from usePolling.ts, which already includes ETag support, 304 handling, tab visibility detection, and proper React lifecycle integration. This consolidation reduces code duplication and improves performance.

Applied to files:

  • archon-ui-main/src/features/knowledge/hooks/useKnowledgeQueries.ts
  • archon-ui-main/src/features/progress/hooks/useProgressQueries.ts
📚 Learning: 2025-09-13T15:53:40.757Z
Learnt from: CR
PR: coleam00/Archon#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-13T15:53:40.757Z
Learning: Applies to archon-ui-main/src/features/**/*.{ts,tsx} : Use useSmartPolling and polling intervals (1–2s active, 5–10s background) with smart pausing on tab inactivity

Applied to files:

  • archon-ui-main/src/features/knowledge/hooks/useKnowledgeQueries.ts
  • archon-ui-main/src/features/progress/hooks/useProgressQueries.ts
📚 Learning: 2025-08-29T08:57:47.558Z
Learnt from: Wirasm
PR: coleam00/Archon#514
File: archon-ui-main/src/services/progressService.ts:0-0
Timestamp: 2025-08-29T08:57:47.558Z
Learning: The progressService.ts file was removed from the codebase in PR #514 as part of the consolidation effort to use the usePolling hook pattern from usePolling.ts instead of maintaining separate polling services. This aligns with the architectural decision to deprecate individual polling services in favor of the centralized hook-based approach.

Applied to files:

  • archon-ui-main/src/features/progress/hooks/useProgressQueries.ts
📚 Learning: 2025-08-28T12:56:47.840Z
Learnt from: Wirasm
PR: coleam00/Archon#514
File: archon-ui-main/src/pages/ProjectPage.tsx:329-331
Timestamp: 2025-08-28T12:56:47.840Z
Learning: In the ProjectPage.tsx polling refactor, temporary project creation logic with progress cards was removed in favor of simpler modal loading states, as the complexity of managing in-flight temporary projects wasn't justified when HTTP polling would show new projects within seconds anyway.

Applied to files:

  • archon-ui-main/src/features/progress/hooks/useProgressQueries.ts
🧬 Code graph analysis (10)
archon-ui-main/src/features/knowledge/services/knowledgeService.ts (1)
archon-ui-main/src/features/knowledge/types/knowledge.ts (1)
  • KnowledgeItem (26-39)
archon-ui-main/src/features/projects/tasks/types/task.ts (1)
archon-ui-main/src/features/projects/tasks/types/index.ts (3)
  • Assignee (11-11)
  • COMMON_ASSIGNEES (24-24)
  • CommonAssignee (12-12)
archon-ui-main/src/features/projects/tasks/components/TaskAssignee.tsx (4)
archon-ui-main/src/features/projects/tasks/types/task.ts (2)
  • Assignee (15-15)
  • COMMON_ASSIGNEES (18-18)
archon-ui-main/src/features/ui/primitives/combobox.tsx (2)
  • ComboBoxOption (15-19)
  • ComboBox (49-360)
archon-ui-main/src/features/projects/tasks/utils/task-styles.tsx (1)
  • getAssigneeIcon (10-21)
archon-ui-main/src/features/ui/primitives/styles.ts (1)
  • cn (139-141)
archon-ui-main/src/features/projects/tasks/components/EditableTableCell.tsx (3)
archon-ui-main/src/features/ui/primitives/combobox.tsx (2)
  • ComboBoxOption (15-19)
  • ComboBox (49-360)
archon-ui-main/src/features/projects/tasks/types/task.ts (1)
  • COMMON_ASSIGNEES (18-18)
archon-ui-main/src/features/ui/primitives/styles.ts (1)
  • cn (139-141)
archon-ui-main/src/features/projects/tasks/components/TaskEditModal.tsx (2)
archon-ui-main/src/features/ui/primitives/combobox.tsx (2)
  • ComboBoxOption (15-19)
  • ComboBox (49-360)
archon-ui-main/src/features/projects/tasks/types/task.ts (1)
  • COMMON_ASSIGNEES (18-18)
archon-ui-main/src/features/ui/primitives/combobox.tsx (2)
archon-ui-main/src/features/ui/primitives/button.tsx (1)
  • Button (11-130)
archon-ui-main/src/features/ui/primitives/styles.ts (1)
  • cn (139-141)
archon-ui-main/src/features/projects/tasks/hooks/useTaskQueries.ts (2)
archon-ui-main/src/features/ui/hooks/useSmartPolling.ts (1)
  • useSmartPolling (8-66)
archon-ui-main/src/features/shared/queryPatterns.ts (2)
  • DISABLED_QUERY_KEY (13-13)
  • STALE_TIMES (17-24)
archon-ui-main/src/features/knowledge/hooks/useKnowledgeQueries.ts (6)
archon-ui-main/src/features/knowledge/types/knowledge.ts (3)
  • KnowledgeItemsFilter (127-134)
  • KnowledgeItem (26-39)
  • KnowledgeItemsResponse (98-103)
archon-ui-main/src/features/shared/queryPatterns.ts (2)
  • DISABLED_QUERY_KEY (13-13)
  • STALE_TIMES (17-24)
archon-ui-main/src/features/knowledge/services/knowledgeService.ts (1)
  • knowledgeService (23-220)
archon-ui-main/src/features/progress/hooks/useProgressQueries.ts (1)
  • progressKeys (15-20)
archon-ui-main/src/features/progress/types/progress.ts (1)
  • ActiveOperationsResponse (105-109)
archon-ui-main/src/features/ui/hooks/useSmartPolling.ts (1)
  • useSmartPolling (8-66)
archon-ui-main/src/features/progress/hooks/useProgressQueries.ts (5)
archon-ui-main/src/features/ui/hooks/useSmartPolling.ts (1)
  • useSmartPolling (8-66)
archon-ui-main/src/features/shared/queryPatterns.ts (2)
  • DISABLED_QUERY_KEY (13-13)
  • STALE_TIMES (17-24)
archon-ui-main/src/features/shared/errors.ts (1)
  • APIServiceError (19-28)
archon-ui-main/src/features/progress/types/progress.ts (2)
  • ActiveOperationsResponse (105-109)
  • ProgressResponse (111-149)
archon-ui-main/src/features/progress/services/progressService.ts (1)
  • progressService (9-24)
archon-ui-main/src/features/knowledge/hooks/tests/useKnowledgeQueries.test.ts (1)
archon-ui-main/src/features/knowledge/hooks/useKnowledgeQueries.ts (2)
  • knowledgeKeys (26-49)
  • useDeleteKnowledgeItem (524-570)

Comment thread archon-ui-main/src/features/knowledge/hooks/useKnowledgeQueries.ts
Comment on lines +130 to +152
// Render ComboBox for assignee type
if (type === "assignee") {
return (
<ComboBox
options={ASSIGNEE_OPTIONS}
value={editValue}
onValueChange={(newValue) => {
setEditValue(newValue);
// Auto-save on change
setTimeout(() => {
onSave(newValue);
setIsEditing(false);
}, 0);
}}
placeholder="Select assignee..."
searchPlaceholder="Assign to..."
emptyMessage="Press Enter to add"
className={cn("w-full h-7 text-sm", className)}
allowCustomValue={true}
disabled={isSaving}
/>
);
}
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

Auto‑save does not await, ignores errors, and doesn’t set isSaving

setTimeout(() => onSave(...), 0) drops error handling and may cause racey double updates. Await the save, set isSaving, and only close on success.

Apply this diff to the onValueChange handler and show loading feedback:

-        onValueChange={(newValue) => {
-          setEditValue(newValue);
-          // Auto-save on change
-          setTimeout(() => {
-            onSave(newValue);
-            setIsEditing(false);
-          }, 0);
-        }}
+        onValueChange={async (newValue) => {
+          setEditValue(newValue);
+          setIsSaving(true);
+          try {
+            await onSave(newValue);
+            setIsEditing(false);
+          } catch (error) {
+            console.error("Failed to save:", error);
+            setEditValue(value);
+          } finally {
+            setIsSaving(false);
+          }
+        }}
+        isLoading={isSaving}

If you prefer reuse, add a local helper and call it here:

// Place inside component, near other handlers
const saveAndClose = async (newValue: string) => {
  if (newValue === value) {
    setIsEditing(false);
    return;
  }
  setIsSaving(true);
  try {
    await onSave(newValue);
    setIsEditing(false);
  } catch (e) {
    console.error("Failed to save:", e);
    setEditValue(value);
  } finally {
    setIsSaving(false);
  }
};
🤖 Prompt for AI Agents
In archon-ui-main/src/features/projects/tasks/components/EditableTableCell.tsx
around lines 130 to 152, the onValueChange currently uses setTimeout(() =>
onSave(...), 0) which neither awaits the save nor sets isSaving or handles
errors; replace that pattern by creating a local async helper (e.g.,
saveAndClose) that returns early if newValue === value, sets setIsSaving(true),
awaits onSave(newValue), on success sets setIsEditing(false), on error logs the
error and restores editValue to the original value, and in finally sets
setIsSaving(false); then call this helper from onValueChange instead of using
setTimeout so the component properly shows loading feedback and avoids racey
double updates.

Add missing implementation for filter_by="assignee" that was documented
but not coded. The filter now properly passes the assignee parameter to
the backend API, matching the existing pattern used for status filtering.

Fixes documentation/implementation mismatch identified by CodeRabbit.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (3)
python/src/mcp_server/features/tasks/task_tools.py (3)

222-227: Docstring: clarify default applies only to create; document unassign semantics.

Explicitly note create-only default and how to clear an assignee to avoid ambiguity.

-            assignee: String name of the assignee. Can be any agent name,
-                     "User" for human assignment, or custom agent identifiers
-                     created by your system (e.g., "ResearchAgent-1", "CodeReviewer").
-                     Common values: "User", "Archon", "Coding Agent"
-                     Default: "User"
+            assignee: String name of the assignee. Can be any agent name,
+                     "User" for human assignment, or custom agent identifiers
+                     created by your system (e.g., "ResearchAgent-1", "CodeReviewer").
+                     Common values: "User", "Archon", "Coding Agent".
+                     Default (create only): "User". Updates leave assignee unchanged unless provided.
+                     Unassign semantics: specify per API (e.g., assignee="" vs null).

231-232: Examples: add an explicit unassign example (once semantics confirmed).

Helps callers discover how to clear an assignee.

   Examples:
     manage_task("create", project_id="p-1", title="Fix auth bug", assignee="CodeAnalyzer-v2")
     manage_task("update", task_id="t-1", status="doing", assignee="User")
+    # If API treats empty string as unassign (confirm this):
+    manage_task("update", task_id="t-1", assignee="")

133-139: Assignee filter: trim whitespace and keep using assignee query param.

Verified: server routes/services, migration, docs and tests use/query assignee and honor include_closed + project_id. Apply this small hardening.

File: python/src/mcp_server/features/tasks/task_tools.py (around lines 133-139)

-elif filter_by == "assignee" and filter_value:
+elif filter_by == "assignee" and filter_value and filter_value.strip():
  # Use generic tasks endpoint for assignee filtering
  url = urljoin(api_url, "/api/tasks")
-  params["assignee"] = filter_value
+  params["assignee"] = filter_value.strip()
  params["include_closed"] = include_closed
  if project_id:
    params["project_id"] = project_id
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 80fc64e and d3f7d04.

📒 Files selected for processing (1)
  • python/src/mcp_server/features/tasks/task_tools.py (2 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
python/src/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

python/src/**/*.py: Fail fast on critical conditions: service startup failures, missing configuration/env vars, database connection/auth failures, critical dependencies unavailable
Never accept or store corrupted data (e.g., zero embeddings, null foreign keys, malformed JSON); skip failed items entirely and continue processing
For batch/background operations, continue processing but log detailed per-item failures; for external APIs use retries with exponential backoff and then fail clearly
Error messages must include context, use specific exception types, preserve full stack traces (logging with exc_info=True), include relevant IDs/URLs, and never return None to indicate failure—raise instead; for batch ops report success counts and detailed failures
Backend uses Python 3.12 with a 120-character line length
Avoid introducing WebSocket support in the backend; updates are handled via HTTP polling
Adhere to Ruff lint rules (e.g., no unused imports) and provide type hints to satisfy MyPy

python/src/**/*.py: Fail fast on service startup failures (credentials, DB, service init); crash with clear errors
Treat missing configuration (env vars/invalid settings) as fatal; stop the system
Do not hide database connection failures; bubble up and surface clearly
Authentication/authorization failures must halt the operation and be visible
Never silently accept bad data; let Pydantic validation errors raise
If critical dependencies are unavailable, fail immediately
Reject invalid data that could corrupt state (e.g., zero embeddings, null FKs, malformed JSON)
Batch processing should complete remaining items but log detailed per-item failures
Background tasks (e.g., embedding generation) should finish queues while logging failures
Treat optional features as skippable: log and skip when disabled rather than crashing
External API calls: use retry with exponential backoff; on final failure, raise with clear service/context info
Never accept corrupted data during partial-failure work...

Files:

  • python/src/mcp_server/features/tasks/task_tools.py
**/*.{py,ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Never return None/null to indicate failure; raise an exception with details instead

Files:

  • python/src/mcp_server/features/tasks/task_tools.py
python/src/mcp_server/features/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

Place MCP tools under python/src/mcp_server/features/[feature]/ named find_[resource] and manage_[resource] patterns

Files:

  • python/src/mcp_server/features/tasks/task_tools.py
🧠 Learnings (1)
📓 Common learnings
Learnt from: CR
PR: coleam00/Archon#0
File: AGENTS.md:0-0
Timestamp: 2025-09-12T13:47:04.545Z
Learning: Applies to archon-ui-main/src/features/**/*.{ts,tsx} : Follow TanStack Query patterns: query-keys factory, smart polling via useSmartPolling, optimistic updates with rollback
Learnt from: CR
PR: coleam00/Archon#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-13T15:53:40.757Z
Learning: Applies to archon-ui-main/src/**/*.{ts,tsx} : Frontend data fetching must use TanStack Query (no prop drilling) with query key factories, smart polling, and optimistic updates with rollback

Changes made:
- Reduced smart polling interval from 60s to 5s for background tabs (better responsiveness)
- Fixed cache coherence bug in knowledge queries (missing limit parameter)
- Standardized "Coding Agent" naming (was inconsistently "AI IDE Agent")
- Improved task queries with 2s polling, type safety, and proper invalidation
- Enhanced combobox accessibility with proper ARIA attributes and IDs
- Delegated useCrawlProgressPolling to useActiveOperations (removed duplication)
- Added exact: true to progress query removals (prevents sibling removal)
- Fixed invalid Tailwind class ml-4.5 to ml-4

All changes align with Phase 2 query key standardization goals and improve
overall code quality, accessibility, and performance.

Co-Authored-By: Claude <noreply@anthropic.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (6)
archon-ui-main/src/features/projects/tasks/utils/task-styles.tsx (2)

10-21: DRY the icon/glow switches with a map.

Reduces duplication and makes adding future assignees safer.

+const ASSIGNEE_STYLES: Record<string, { icon: JSX.Element; glow: string }> = {
+  User: { icon: <User className="w-4 h-4 text-blue-400" />, glow: "shadow-[0_0_10px_rgba(59,130,246,0.4)]" },
+  "Coding Agent": { icon: <Bot className="w-4 h-4 text-purple-400" />, glow: "shadow-[0_0_10px_rgba(168,85,247,0.4)]" },
+  Archon: { icon: <img src="/logo-neon.png" alt="Archon" className="w-4 h-4" />, glow: "shadow-[0_0_10px_rgba(34,211,238,0.4)]" },
+};
+
 export const getAssigneeIcon = (assigneeName: Assignee) => {
-  switch (assigneeName) {
-    case "User":
-      return <User className="w-4 h-4 text-blue-400" />;
-    case "Coding Agent":
-      return <Bot className="w-4 h-4 text-purple-400" />;
-    case "Archon":
-      return <img src="/logo-neon.png" alt="Archon" className="w-4 h-4" />;
-    default:
-      return <User className="w-4 h-4 text-blue-400" />;
-  }
+  return (ASSIGNEE_STYLES[assigneeName]?.icon ?? ASSIGNEE_STYLES["User"].icon);
 };
 
 export const getAssigneeGlow = (assigneeName: Assignee) => {
-  switch (assigneeName) {
-    case "User":
-      return "shadow-[0_0_10px_rgba(59,130,246,0.4)]";
-    case "Coding Agent":
-      return "shadow-[0_0_10px_rgba(168,85,247,0.4)]";
-    case "Archon":
-      return "shadow-[0_0_10px_rgba(34,211,238,0.4)]";
-    default:
-      return "shadow-[0_0_10px_rgba(59,130,246,0.4)]";
-  }
+  return (ASSIGNEE_STYLES[assigneeName]?.glow ?? ASSIGNEE_STYLES["User"].glow);
 };

Also applies to: 24-35


54-65: Add an explicit fallback or exhaustive check for future statuses.

If new statuses are added later, these functions would return undefined. Consider a default branch or an assertNever helper.

   switch (status) {
     case "todo":
       return "text-gray-600 dark:text-gray-400";
     case "doing":
       return "text-blue-600 dark:text-blue-400";
     case "review":
       return "text-purple-600 dark:text-purple-400";
     case "done":
       return "text-green-600 dark:text-green-400";
+    default:
+      return "text-gray-600 dark:text-gray-400";
   }

(Same idea for getColumnGlow.)

Also applies to: 68-79

PRPs/ai_docs/API_NAMING_CONVENTIONS.md (1)

152-159: Update polling guidance to useSmartPolling to match v5 patterns.

Docs still mention usePolling; project guidance and PR objectives standardize on useSmartPolling.

-### Polling & Data Fetching
-- HTTP polling with `usePolling` and `useCrawlProgressPolling` hooks
+### Polling & Data Fetching
+- HTTP polling with `useSmartPolling` (active 1–2s, background 5–10s) and `useCrawlProgressPolling` hooks
archon-ui-main/src/features/projects/tasks/hooks/useTaskQueries.ts (1)

65-69: Consider removing the hardcoded assignee default.

The comment indicates this is temporary, but hardcoding "User" as a default assignee value could cause confusion. Consider either using null/undefined or deriving a more meaningful default from the current user context.

-        assignee: newTaskData.assignee ?? "User", // Keep for now as UI needs a value for optimistic update
+        assignee: newTaskData.assignee ?? null, // Let UI components handle display of unassigned tasks
archon-ui-main/src/features/progress/hooks/useProgressQueries.ts (1)

238-239: Consider extracting the sorted key generation to a utility.

The sorted JSON stringification for stable dependency is a clever solution for handling array reordering. Consider extracting this pattern to a shared utility if it's used elsewhere.

-  const progressIdsKey = useMemo(() => JSON.stringify([...progressIds].sort()), [progressIds]);
+  const progressIdsKey = useMemo(() => createStableKey(progressIds), [progressIds]);

Then add a utility function:

// In a shared utils file
export function createStableKey<T>(items: T[]): string {
  return JSON.stringify([...items].sort());
}
archon-ui-main/src/features/knowledge/hooks/useKnowledgeQueries.ts (1)

519-520: Type safety improvement needed for error handling.

The TODO correctly identifies the need for better error type safety. Using as any weakens TypeScript's guarantees.

Consider creating a proper error interface:

interface APIError extends Error {
  statusCode?: number;
  status?: number;
  response?: {
    status?: number;
  };
}

Then use it:

-      const is404Error =
-        (error as any)?.statusCode === 404 ||
+      const apiError = error as APIError;
+      const is404Error =
+        apiError?.statusCode === 404 ||
+        apiError?.status === 404 ||
+        apiError?.response?.status === 404 ||
         (error instanceof Error && (error.message.includes("404") || error.message.includes("not found")));
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d3f7d04 and ea86218.

📒 Files selected for processing (9)
  • PRPs/ai_docs/API_NAMING_CONVENTIONS.md (1 hunks)
  • archon-ui-main/src/features/knowledge/hooks/useKnowledgeQueries.ts (31 hunks)
  • archon-ui-main/src/features/progress/hooks/useProgressQueries.ts (14 hunks)
  • archon-ui-main/src/features/projects/tasks/components/TaskEditModal.tsx (4 hunks)
  • archon-ui-main/src/features/projects/tasks/hooks/useTaskQueries.ts (10 hunks)
  • archon-ui-main/src/features/projects/tasks/services/tests/taskService.test.ts (1 hunks)
  • archon-ui-main/src/features/projects/tasks/utils/task-styles.tsx (2 hunks)
  • archon-ui-main/src/features/ui/hooks/useSmartPolling.ts (1 hunks)
  • archon-ui-main/src/features/ui/primitives/combobox.tsx (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • archon-ui-main/src/features/ui/primitives/combobox.tsx
  • archon-ui-main/src/features/projects/tasks/components/TaskEditModal.tsx
🧰 Additional context used
📓 Path-based instructions (5)
archon-ui-main/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

archon-ui-main/src/**/*.{ts,tsx}: Use TanStack Query for all data fetching; avoid prop drilling
TypeScript: strict mode with no implicit any in frontend code
State naming: is[Action]ing for loading flags, [resource]Error for errors, selected[Resource] for current selection
Use HTTP polling with ETag caching; do not introduce WebSocket-based updates in the frontend

archon-ui-main/src/**/*.{ts,tsx}: WebSocket event failures (if any) should be logged and not crash the client; continue serving others
Frontend data fetching must use TanStack Query (no prop drilling) with query key factories, smart polling, and optimistic updates with rollback
Use vertical slice architecture: place UI under src/features/[feature]/(components|hooks|services|types)
State naming: use is[Action]ing for loading, [resource]Error for errors, selected[Resource] for selections
Service method names: get[Resource]sByProject(projectId), getResource, create/update/delete patterns
Frontend TypeScript should be strict (no implicit any)

Files:

  • archon-ui-main/src/features/projects/tasks/services/tests/taskService.test.ts
  • archon-ui-main/src/features/ui/hooks/useSmartPolling.ts
  • archon-ui-main/src/features/projects/tasks/utils/task-styles.tsx
  • archon-ui-main/src/features/knowledge/hooks/useKnowledgeQueries.ts
  • archon-ui-main/src/features/progress/hooks/useProgressQueries.ts
  • archon-ui-main/src/features/projects/tasks/hooks/useTaskQueries.ts
archon-ui-main/src/features/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

archon-ui-main/src/features/**/*.{ts,tsx}: Follow TanStack Query patterns: query-keys factory, smart polling via useSmartPolling, optimistic updates with rollback
Biome formatting in features: 120-character lines, double quotes, trailing commas

archon-ui-main/src/features/**/*.{ts,tsx}: Use Biome formatting/conventions in /src/features: 120-char lines, double quotes, trailing commas
Use useSmartPolling and polling intervals (1–2s active, 5–10s background) with smart pausing on tab inactivity
Expose progress via dedicated hooks (e.g., useCrawlProgressPolling, useProjectTasks) instead of ad-hoc timers
Do not use prop drilling for data fetching/state; rely on TanStack Query caches/selectors

Files:

  • archon-ui-main/src/features/projects/tasks/services/tests/taskService.test.ts
  • archon-ui-main/src/features/ui/hooks/useSmartPolling.ts
  • archon-ui-main/src/features/projects/tasks/utils/task-styles.tsx
  • archon-ui-main/src/features/knowledge/hooks/useKnowledgeQueries.ts
  • archon-ui-main/src/features/progress/hooks/useProgressQueries.ts
  • archon-ui-main/src/features/projects/tasks/hooks/useTaskQueries.ts
archon-ui-main/src/features/**/services/**/*.ts

📄 CodeRabbit inference engine (AGENTS.md)

Frontend service method naming: get[Resource]sByProject(projectId), getResource, createResource, update[Resource](id, updates), deleteResource

Files:

  • archon-ui-main/src/features/projects/tasks/services/tests/taskService.test.ts
**/*.{py,ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Never return None/null to indicate failure; raise an exception with details instead

Files:

  • archon-ui-main/src/features/projects/tasks/services/tests/taskService.test.ts
  • archon-ui-main/src/features/ui/hooks/useSmartPolling.ts
  • archon-ui-main/src/features/projects/tasks/utils/task-styles.tsx
  • archon-ui-main/src/features/knowledge/hooks/useKnowledgeQueries.ts
  • archon-ui-main/src/features/progress/hooks/useProgressQueries.ts
  • archon-ui-main/src/features/projects/tasks/hooks/useTaskQueries.ts
archon-ui-main/src/**/*.{test,spec}.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Write frontend tests with Vitest and React Testing Library

Files:

  • archon-ui-main/src/features/projects/tasks/services/tests/taskService.test.ts
🧠 Learnings (12)
📓 Common learnings
Learnt from: CR
PR: coleam00/Archon#0
File: AGENTS.md:0-0
Timestamp: 2025-09-12T13:47:04.545Z
Learning: Applies to archon-ui-main/src/features/**/*.{ts,tsx} : Follow TanStack Query patterns: query-keys factory, smart polling via useSmartPolling, optimistic updates with rollback
Learnt from: CR
PR: coleam00/Archon#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-13T15:53:40.757Z
Learning: Applies to archon-ui-main/src/**/*.{ts,tsx} : Frontend data fetching must use TanStack Query (no prop drilling) with query key factories, smart polling, and optimistic updates with rollback
📚 Learning: 2025-09-13T15:53:40.757Z
Learnt from: CR
PR: coleam00/Archon#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-13T15:53:40.757Z
Learning: Applies to archon-ui-main/src/features/**/*.{ts,tsx} : Use useSmartPolling and polling intervals (1–2s active, 5–10s background) with smart pausing on tab inactivity

Applied to files:

  • archon-ui-main/src/features/ui/hooks/useSmartPolling.ts
  • archon-ui-main/src/features/knowledge/hooks/useKnowledgeQueries.ts
  • archon-ui-main/src/features/progress/hooks/useProgressQueries.ts
📚 Learning: 2025-09-12T13:47:04.545Z
Learnt from: CR
PR: coleam00/Archon#0
File: AGENTS.md:0-0
Timestamp: 2025-09-12T13:47:04.545Z
Learning: Applies to archon-ui-main/src/**/*.{ts,tsx} : Use HTTP polling with ETag caching; do not introduce WebSocket-based updates in the frontend

Applied to files:

  • archon-ui-main/src/features/ui/hooks/useSmartPolling.ts
📚 Learning: 2025-08-28T13:50:10.499Z
Learnt from: Wirasm
PR: coleam00/Archon#514
File: archon-ui-main/src/services/pollingService.ts:38-45
Timestamp: 2025-08-28T13:50:10.499Z
Learning: The pollingService.ts file is being deprecated in favor of the usePolling hook from usePolling.ts. The team has decided to consolidate on the usePolling hook pattern rather than maintaining separate polling services, as it provides better React integration and reduces code duplication.

Applied to files:

  • archon-ui-main/src/features/ui/hooks/useSmartPolling.ts
  • archon-ui-main/src/features/progress/hooks/useProgressQueries.ts
📚 Learning: 2025-09-12T13:47:04.545Z
Learnt from: CR
PR: coleam00/Archon#0
File: AGENTS.md:0-0
Timestamp: 2025-09-12T13:47:04.545Z
Learning: Applies to archon-ui-main/src/features/**/*.{ts,tsx} : Follow TanStack Query patterns: query-keys factory, smart polling via useSmartPolling, optimistic updates with rollback

Applied to files:

  • archon-ui-main/src/features/ui/hooks/useSmartPolling.ts
  • archon-ui-main/src/features/knowledge/hooks/useKnowledgeQueries.ts
  • archon-ui-main/src/features/progress/hooks/useProgressQueries.ts
  • archon-ui-main/src/features/projects/tasks/hooks/useTaskQueries.ts
📚 Learning: 2025-08-28T13:51:59.203Z
Learnt from: Wirasm
PR: coleam00/Archon#514
File: archon-ui-main/src/services/pollingService.ts:60-102
Timestamp: 2025-08-28T13:51:59.203Z
Learning: The pollingService.ts file was removed from the codebase after initially being added in PR #514, confirming the team's decision to consolidate on the usePolling hook pattern rather than maintaining separate polling services.

Applied to files:

  • archon-ui-main/src/features/ui/hooks/useSmartPolling.ts
📚 Learning: 2025-08-28T13:07:24.810Z
Learnt from: Wirasm
PR: coleam00/Archon#514
File: archon-ui-main/src/services/crawlProgressService.ts:35-39
Timestamp: 2025-08-28T13:07:24.810Z
Learning: The crawlProgressService.ts in the Archon codebase should be deprecated in favor of the existing useCrawlProgressPolling hook from usePolling.ts, which already includes ETag support, 304 handling, tab visibility detection, and proper React lifecycle integration. This consolidation reduces code duplication and improves performance.

Applied to files:

  • archon-ui-main/src/features/ui/hooks/useSmartPolling.ts
  • archon-ui-main/src/features/knowledge/hooks/useKnowledgeQueries.ts
  • archon-ui-main/src/features/progress/hooks/useProgressQueries.ts
📚 Learning: 2025-09-13T15:53:40.757Z
Learnt from: CR
PR: coleam00/Archon#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-13T15:53:40.757Z
Learning: Applies to archon-ui-main/src/features/**/*.{ts,tsx} : Expose progress via dedicated hooks (e.g., useCrawlProgressPolling, useProjectTasks) instead of ad-hoc timers

Applied to files:

  • archon-ui-main/src/features/ui/hooks/useSmartPolling.ts
  • archon-ui-main/src/features/knowledge/hooks/useKnowledgeQueries.ts
  • archon-ui-main/src/features/progress/hooks/useProgressQueries.ts
  • archon-ui-main/src/features/projects/tasks/hooks/useTaskQueries.ts
📚 Learning: 2025-08-29T08:57:47.558Z
Learnt from: Wirasm
PR: coleam00/Archon#514
File: archon-ui-main/src/services/progressService.ts:0-0
Timestamp: 2025-08-29T08:57:47.558Z
Learning: The progressService.ts file was removed from the codebase in PR #514 as part of the consolidation effort to use the usePolling hook pattern from usePolling.ts instead of maintaining separate polling services. This aligns with the architectural decision to deprecate individual polling services in favor of the centralized hook-based approach.

Applied to files:

  • archon-ui-main/src/features/ui/hooks/useSmartPolling.ts
  • archon-ui-main/src/features/progress/hooks/useProgressQueries.ts
📚 Learning: 2025-08-28T13:51:59.203Z
Learnt from: Wirasm
PR: coleam00/Archon#514
File: archon-ui-main/src/services/pollingService.ts:60-102
Timestamp: 2025-08-28T13:51:59.203Z
Learning: The pollingService.ts file exists physically but is unused dead code in PR #514. It's only referenced in documentation but not imported anywhere in the TypeScript codebase. The actual polling implementation uses the usePolling hook from usePolling.ts instead.

Applied to files:

  • archon-ui-main/src/features/ui/hooks/useSmartPolling.ts
📚 Learning: 2025-09-13T15:53:40.757Z
Learnt from: CR
PR: coleam00/Archon#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-13T15:53:40.757Z
Learning: Applies to archon-ui-main/src/**/*.{ts,tsx} : Frontend data fetching must use TanStack Query (no prop drilling) with query key factories, smart polling, and optimistic updates with rollback

Applied to files:

  • archon-ui-main/src/features/knowledge/hooks/useKnowledgeQueries.ts
  • archon-ui-main/src/features/progress/hooks/useProgressQueries.ts
  • archon-ui-main/src/features/projects/tasks/hooks/useTaskQueries.ts
📚 Learning: 2025-08-28T12:56:47.840Z
Learnt from: Wirasm
PR: coleam00/Archon#514
File: archon-ui-main/src/pages/ProjectPage.tsx:329-331
Timestamp: 2025-08-28T12:56:47.840Z
Learning: In the ProjectPage.tsx polling refactor, temporary project creation logic with progress cards was removed in favor of simpler modal loading states, as the complexity of managing in-flight temporary projects wasn't justified when HTTP polling would show new projects within seconds anyway.

Applied to files:

  • archon-ui-main/src/features/progress/hooks/useProgressQueries.ts
  • archon-ui-main/src/features/projects/tasks/hooks/useTaskQueries.ts
🧬 Code graph analysis (3)
archon-ui-main/src/features/knowledge/hooks/useKnowledgeQueries.ts (6)
archon-ui-main/src/features/knowledge/types/knowledge.ts (3)
  • KnowledgeItemsFilter (127-134)
  • KnowledgeItem (26-39)
  • KnowledgeItemsResponse (98-103)
archon-ui-main/src/features/shared/queryPatterns.ts (2)
  • DISABLED_QUERY_KEY (13-13)
  • STALE_TIMES (17-24)
archon-ui-main/src/features/knowledge/services/knowledgeService.ts (1)
  • knowledgeService (23-220)
archon-ui-main/src/features/progress/hooks/useProgressQueries.ts (1)
  • progressKeys (15-20)
archon-ui-main/src/features/progress/types/progress.ts (1)
  • ActiveOperationsResponse (105-109)
archon-ui-main/src/features/ui/hooks/useSmartPolling.ts (1)
  • useSmartPolling (8-66)
archon-ui-main/src/features/progress/hooks/useProgressQueries.ts (5)
archon-ui-main/src/features/ui/hooks/useSmartPolling.ts (1)
  • useSmartPolling (8-66)
archon-ui-main/src/features/shared/queryPatterns.ts (2)
  • DISABLED_QUERY_KEY (13-13)
  • STALE_TIMES (17-24)
archon-ui-main/src/features/shared/errors.ts (1)
  • APIServiceError (19-28)
archon-ui-main/src/features/progress/types/progress.ts (2)
  • ActiveOperationsResponse (105-109)
  • ProgressResponse (111-149)
archon-ui-main/src/features/progress/services/progressService.ts (1)
  • progressService (9-24)
archon-ui-main/src/features/projects/tasks/hooks/useTaskQueries.ts (2)
archon-ui-main/src/features/ui/hooks/useSmartPolling.ts (1)
  • useSmartPolling (8-66)
archon-ui-main/src/features/shared/queryPatterns.ts (2)
  • DISABLED_QUERY_KEY (13-13)
  • STALE_TIMES (17-24)
🔇 Additional comments (14)
PRPs/ai_docs/API_NAMING_CONVENTIONS.md (1)

112-114: Docs updated to flexible Assignee = string; looks good.

The comment listing common values matches current UI/fixtures.

archon-ui-main/src/features/projects/tasks/utils/task-styles.tsx (1)

14-15: Rename to "Coding Agent" is consistent — no "AI IDE Agent" occurrences found.

Matches found in: archon-ui-main/src/features/projects/tasks/utils/task-styles.tsx; archon-ui-main/src/features/projects/tasks/types/task.ts (COMMON_ASSIGNEES); archon-ui-main/src/features/projects/tasks/components/TaskEditModal.tsx; archon-ui-main/src/features/projects/tasks/components/TaskAssignee.tsx; archon-ui-main/src/features/projects/tasks/services/tests/taskService.test.ts; PRPs/ai_docs/API_NAMING_CONVENTIONS.md; python/src/mcp_server/features/tasks/task_tools.py.

archon-ui-main/src/features/projects/tasks/services/tests/taskService.test.ts (1)

279-287: Approve — "Coding Agent" fixture rename verified.
Repo-wide search for "AI IDE Agent" found no matches; rename aligns with Assignee = string and COMMON_ASSIGNEES.

archon-ui-main/src/features/ui/hooks/useSmartPolling.ts (1)

52-53: Background polling interval aligns with guidelines.

The change from 60 seconds to 5 seconds for background polling is appropriate and consistent with the 5-10s background polling guideline mentioned in the coding guidelines. This also matches STALE_TIMES.frequent (5000ms) in the shared query patterns.

archon-ui-main/src/features/projects/tasks/hooks/useTaskQueries.ts (3)

8-15: Well-structured query keys factory implementation.

The refactored taskKeys factory provides excellent organization with clear separation between different query types (lists, detail, byProject, counts). The comment explaining the dual backend nature is helpful for maintainability.


19-19: Appropriate polling interval for real-time task updates.

The 2-second polling interval aligns with the "1-2s active" guideline for real-time data and is appropriate for task updates that users expect to see quickly.


145-147: Smart status-based cache invalidation.

Good optimization to only invalidate task counts when the status changes, as that's the only field affecting counts. This reduces unnecessary API calls.

archon-ui-main/src/features/progress/hooks/useProgressQueries.ts (3)

15-20: Clean query keys factory with proper hierarchy.

The factory structure follows best practices with lists(), detail(id), and active() providing clear query boundaries. The naming is intuitive and follows the established pattern.


60-65: Comprehensive 404 error detection.

Excellent defensive programming with multiple fallback checks for 404 errors across different error object shapes. This ensures robustness across various API client implementations.


112-118: Well-structured timer cleanup with exact query removal.

Good use of exact query matching and centralized timer management. The 2-second delay before cleanup is reasonable for completion scenarios.

archon-ui-main/src/features/knowledge/hooks/useKnowledgeQueries.ts (4)

29-49: Excellent implementation addressing past review feedback.

The query keys factory now properly includes pagination parameters in chunks() and codeExamples(), and provides summariesPrefix() for stable cache targeting. This addresses all the concerns from previous reviews about cache collisions and identity issues.


148-154: Safe hostname extraction with fallback.

Good defensive programming with try-catch around URL parsing and appropriate fallback to "New crawl" when URL parsing fails.


617-624: Tags correctly updated in metadata only.

Good implementation ensuring tags are stored in metadata rather than at the top level, maintaining data consistency.


774-776: Smart polling frequency adjustment based on active operations.

Excellent use of conditional polling intervals - faster polling (5s) when operations are active, slower (30s) when idle. This optimizes API usage while maintaining responsiveness.

Comment on lines +121 to +127
// TODO: Phase 3 - Fix optimistic updates writing to wrong cache
// knowledgeKeys.lists() is never queried - actual data comes from knowledgeKeys.summaries(filter)
// This makes all optimistic updates invisible. Should either:
// 1. Remove optimistic updates for knowledge items
// 2. Update all summary caches with optimistic data
// 3. Create a real query that uses lists()
// See: PRPs/local/frontend-state-management-refactor.md Phase 3
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

Important TODO: Fix optimistic updates targeting wrong cache.

The TODO correctly identifies that optimistic updates to knowledgeKeys.lists() are invisible because the UI actually queries knowledgeKeys.summaries(filter). This is a significant UX issue where users won't see their optimistic updates.

Consider implementing one of the suggested solutions:

  1. Recommended: Update all relevant summary caches based on filter matching
  2. Remove optimistic updates entirely if proper implementation is complex
  3. Create a dedicated query that uses lists() for the main view

The current implementation in lines 187-202 attempts to update all summary caches but doesn't check filter criteria, which could cause items to appear in filtered views where they shouldn't.

🤖 Prompt for AI Agents
In archon-ui-main/src/features/knowledge/hooks/useKnowledgeQueries.ts around
lines 121-127 (and where optimistic updates are applied around lines 187-202),
optimistic updates are currently written to knowledgeKeys.lists() while the UI
reads knowledgeKeys.summaries(filter), making updates invisible or incorrectly
showing items in filtered views; modify the optimistic update logic to locate
all cached summaries entries and only update those whose filter predicate would
include the new/updated item (e.g., evaluate each cache entry’s filter against
the item and add/update/remove it accordingly), or if that is too complex remove
optimistic updates for knowledge items or create a dedicated lists() query used
by the main view—ensure any mutation handler updates summary caches
conditionally based on each summary’s filter to avoid leaking items into
unrelated filtered views.

Comment on lines +183 to +186
// Currently adds items to ALL summary caches regardless of their filters (e.g., knowledge_type, tags).
// This can cause items to appear in filtered views where they shouldn't be visible.
// Solution: Check each cache's filter criteria before adding the optimistic item.
// See: https://github.com/coleam00/Archon/pull/676#issuecomment-XXXXX
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

Filter-blind optimistic updates need fixing.

The TODO correctly identifies that items are added to ALL summary caches regardless of their filter criteria. This could cause items to appear in views where they don't belong (e.g., a "technical" item appearing in a "business" filter).

Consider checking filter criteria before adding to each cache:

queryClient.setQueriesData<KnowledgeItemsResponse>({ queryKey: knowledgeKeys.summariesPrefix() }, (old, queryKey) => {
+  // Extract filter from query key if present
+  const filter = queryKey[2] as KnowledgeItemsFilter | undefined;
+  
+  // Check if optimistic item matches the filter
+  if (filter?.knowledge_type && filter.knowledge_type !== optimisticItem.knowledge_type) {
+    return old; // Don't add to this filtered cache
+  }
+  if (filter?.tags && !filter.tags.some(tag => optimisticItem.metadata.tags?.includes(tag))) {
+    return old; // Item doesn't match tag filter
+  }
+  
   if (!old) {
     return {
       items: [optimisticItem],

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In archon-ui-main/src/features/knowledge/hooks/useKnowledgeQueries.ts around
lines 183 to 186, the optimistic-update currently pushes new items into every
summary cache regardless of that cache's filter settings; change the logic to
iterate the relevant summary caches, extract each cache's filter criteria (e.g.,
knowledge_type, tags, search params) from the cache key or stored query meta,
evaluate whether the optimistic item satisfies those criteria, and only add it
to caches where it matches; also update any cache totals/metadata consistently
(and ensure the optimistic patch is reversible on rollback or error).

@Wirasm Wirasm merged commit f4ad785 into main Sep 18, 2025
16 checks passed
@Wirasm Wirasm deleted the refactor/phase-2-query-keys-standardization branch September 18, 2025 08:05
leonj1 pushed a commit to leonj1/Archon that referenced this pull request Oct 13, 2025
…y v5 patterns implementation (coleam00#692)

* refactor: complete Phase 2 Query Keys Standardization

Standardize query keys across all features following vertical slice architecture,
ensuring they mirror backend API structure exactly with no backward compatibility.

Key Changes:
- Refactor all query key factories to follow consistent patterns
- Move progress feature from knowledge/progress to top-level /features/progress
- Create shared query patterns for consistency (DISABLED_QUERY_KEY, STALE_TIMES)
- Remove all hardcoded stale times and disabled keys
- Update all imports after progress feature relocation

Query Key Factories Standardized:
- projectKeys: removed task-related keys (tasks, taskCounts)
- taskKeys: added dual nature support (global via lists(), project-scoped via byProject())
- knowledgeKeys: removed redundant methods (details, summary)
- progressKeys: new top-level feature with consistent factory
- documentKeys: full factory pattern with versions support
- mcpKeys: complete with health endpoint

Shared Patterns Implementation:
- STALE_TIMES: instant (0), realtime (3s), frequent (5s), normal (30s), rare (5m), static (∞)
- DISABLED_QUERY_KEY: consistent disabled query pattern across all features
- Removed unused createQueryOptions helper

Testing:
- Added comprehensive tests for progress hooks
- Updated all test mocks to include new STALE_TIMES values
- All 81 feature tests passing

Documentation:
- Created QUERY_PATTERNS.md guide for future implementations
- Clear patterns, examples, and migration checklist

Breaking Changes:
- Progress imports moved from knowledge/progress to progress
- Query key structure changes (cache will reset)
- No backward compatibility maintained

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: establish single source of truth for tags in metadata

- Remove ambiguous top-level tags field from KnowledgeItem interface
- Update all UI components to use metadata.tags exclusively
- Fix mutations to correctly update tags in metadata object
- Remove duplicate tags field from backend KnowledgeSummaryService
- Fix test setup issue with QueryClient instance in knowledge tests
- Add TODO comments for filter-blind optimistic updates (Phase 3)

This eliminates the ambiguity identified in Phase 2 where both item.tags
and metadata.tags existed, establishing metadata.tags as the single
source of truth across the entire stack.

* fix: comprehensive progress hooks improvements

- Integrate useSmartPolling for all polling queries
- Fix memory leaks from uncleaned timeouts
- Replace string-based error checking with status codes
- Remove TypeScript any usage with proper types
- Fix unstable dependencies with sorted JSON serialization
- Add staleTime to document queries for consistency

* feat: implement flexible assignee system for dynamic agents

- Changed assignee from restricted enum to flexible string type
- Renamed "AI IDE Agent" to "Coding Agent" for clarity
- Enhanced ComboBox with Radix UI best practices:
  - Full ARIA compliance (roles, labels, keyboard nav)
  - Performance optimizations (memoization, useCallback)
  - Improved UX (auto-scroll, keyboard shortcuts)
  - Fixed event bubbling preventing unintended modal opens
- Updated MCP server docs to reflect flexible assignee capability
- Removed unnecessary UI elements (arrows, helper text)
- Styled ComboBox to match priority selector aesthetic

This allows external MCP clients to create and assign custom sub-agents
dynamically, supporting advanced agent orchestration workflows.

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: complete Phase 2 summariesPrefix usage for cache consistency

- Fix all knowledgeKeys.summaries() calls to use summariesPrefix() for operations targeting multiple summary caches
- Update cancelQueries, getQueriesData, setQueriesData, invalidateQueries, and refetchQueries calls
- Fix critical cache invalidation bug where filtered summaries weren't being cleared
- Update test expectations to match new factory patterns
- Address CodeRabbit review feedback on cache stability issues

This completes the Phase 2 Query Keys Standardization work documented in PRPs/local/frontend-state-management-refactor.md

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: update MCP task tools documentation for Coding Agent rename

Update task assignee documentation from "AI IDE Agent" to "Coding Agent"
to match frontend changes for consistency across the system.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: implement assignee filtering in MCP find_tasks function

Add missing implementation for filter_by="assignee" that was documented
but not coded. The filter now properly passes the assignee parameter to
the backend API, matching the existing pattern used for status filtering.

Fixes documentation/implementation mismatch identified by CodeRabbit.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: Phase 2 cleanup - address review comments and improve code quality

Changes made:
- Reduced smart polling interval from 60s to 5s for background tabs (better responsiveness)
- Fixed cache coherence bug in knowledge queries (missing limit parameter)
- Standardized "Coding Agent" naming (was inconsistently "AI IDE Agent")
- Improved task queries with 2s polling, type safety, and proper invalidation
- Enhanced combobox accessibility with proper ARIA attributes and IDs
- Delegated useCrawlProgressPolling to useActiveOperations (removed duplication)
- Added exact: true to progress query removals (prevents sibling removal)
- Fixed invalid Tailwind class ml-4.5 to ml-4

All changes align with Phase 2 query key standardization goals and improve
overall code quality, accessibility, and performance.

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
coleam00 pushed a commit that referenced this pull request Apr 7, 2026
)

* feat: default worktree isolation for CLI + auto-detect base branch

- CLI now creates a worktree by default (matching all other adapters)
- Branch names auto-generated as {workflowName}-{timestamp}
- --no-worktree opts out of isolation (standalone flag, no longer requires --branch)
- All generated branch names prefixed with archon/ for clear namespace
- Base branch auto-detected from git (symbolic-ref → origin/main → origin/master)
- Config worktree.baseBranch still overrides auto-detection
- $BASE_BRANCH in workflow prompts auto-resolves without config
- Ignore .claude/skills/ from ESLint

* fix: address PR review findings — error handling, tests, docs

- Add warn log for silent getDefaultBranch catch in executor.ts
- Fix branchToSync bug: don't pass fromBranch as sync target
  (fromBranch is the worktree start-point, not the base to sync)
- Add user-facing warning when isolation is silently skipped
- Add errorType to codebase_auto_registration_failed log
- Consolidate all validation guards in workflowRunCommand
  (cli.ts keeps them for UX fast-path, workflowRunCommand is
  the authoritative boundary for programmatic callers)
- Add tests: validation guards, default isolation, --no-worktree
  skip, isolation-skipped warning, auto-detect $BASE_BRANCH success
- Add loadRepoConfig to @archon/core mock in workflow tests
- Update docs: CLAUDE.md, cli-user-guide, configuration,
  authoring-workflows, worktree-orchestration, README, cli.md rule
  — all updated for default isolation, archon/ prefix, optional
  baseBranch with auto-detection

* refactor: simplify isolation branch logic and fix log naming

- Split shouldIsolate into wantsIsolation + codebase check to
  eliminate redundant double-check of codebase
- Simplify else-if chain: use wantsIsolation instead of re-testing
  already-false conditions
- Deduplicate isolation-skipped warning messages
- Fix log event: base_branch.auto_detect_failed →
  workflow.base_branch_auto_detect_failed (project naming convention)

* fix: fail fast when isolation cannot be created instead of silent fallback

When the user hasn't opted out with --no-worktree, failing to create
a worktree (DB error or not in a git repo) now throws instead of
silently running in the live checkout. This prevents AI from making
unprotected changes to the working tree.

* chore: Auto-commit workflow artifacts (archon-assist)
Tyone88 pushed a commit to Tyone88/Archon that referenced this pull request Apr 16, 2026
…oleam00#692)

* feat: default worktree isolation for CLI + auto-detect base branch

- CLI now creates a worktree by default (matching all other adapters)
- Branch names auto-generated as {workflowName}-{timestamp}
- --no-worktree opts out of isolation (standalone flag, no longer requires --branch)
- All generated branch names prefixed with archon/ for clear namespace
- Base branch auto-detected from git (symbolic-ref → origin/main → origin/master)
- Config worktree.baseBranch still overrides auto-detection
- $BASE_BRANCH in workflow prompts auto-resolves without config
- Ignore .claude/skills/ from ESLint

* fix: address PR review findings — error handling, tests, docs

- Add warn log for silent getDefaultBranch catch in executor.ts
- Fix branchToSync bug: don't pass fromBranch as sync target
  (fromBranch is the worktree start-point, not the base to sync)
- Add user-facing warning when isolation is silently skipped
- Add errorType to codebase_auto_registration_failed log
- Consolidate all validation guards in workflowRunCommand
  (cli.ts keeps them for UX fast-path, workflowRunCommand is
  the authoritative boundary for programmatic callers)
- Add tests: validation guards, default isolation, --no-worktree
  skip, isolation-skipped warning, auto-detect $BASE_BRANCH success
- Add loadRepoConfig to @archon/core mock in workflow tests
- Update docs: CLAUDE.md, cli-user-guide, configuration,
  authoring-workflows, worktree-orchestration, README, cli.md rule
  — all updated for default isolation, archon/ prefix, optional
  baseBranch with auto-detection

* refactor: simplify isolation branch logic and fix log naming

- Split shouldIsolate into wantsIsolation + codebase check to
  eliminate redundant double-check of codebase
- Simplify else-if chain: use wantsIsolation instead of re-testing
  already-false conditions
- Deduplicate isolation-skipped warning messages
- Fix log event: base_branch.auto_detect_failed →
  workflow.base_branch_auto_detect_failed (project naming convention)

* fix: fail fast when isolation cannot be created instead of silent fallback

When the user hasn't opted out with --no-worktree, failing to create
a worktree (DB error or not in a git repo) now throws instead of
silently running in the live checkout. This prevents AI from making
unprotected changes to the working tree.

* chore: Auto-commit workflow artifacts (archon-assist)
joaobmonteiro pushed a commit to joaobmonteiro/Archon that referenced this pull request Apr 26, 2026
…oleam00#692)

* feat: default worktree isolation for CLI + auto-detect base branch

- CLI now creates a worktree by default (matching all other adapters)
- Branch names auto-generated as {workflowName}-{timestamp}
- --no-worktree opts out of isolation (standalone flag, no longer requires --branch)
- All generated branch names prefixed with archon/ for clear namespace
- Base branch auto-detected from git (symbolic-ref → origin/main → origin/master)
- Config worktree.baseBranch still overrides auto-detection
- $BASE_BRANCH in workflow prompts auto-resolves without config
- Ignore .claude/skills/ from ESLint

* fix: address PR review findings — error handling, tests, docs

- Add warn log for silent getDefaultBranch catch in executor.ts
- Fix branchToSync bug: don't pass fromBranch as sync target
  (fromBranch is the worktree start-point, not the base to sync)
- Add user-facing warning when isolation is silently skipped
- Add errorType to codebase_auto_registration_failed log
- Consolidate all validation guards in workflowRunCommand
  (cli.ts keeps them for UX fast-path, workflowRunCommand is
  the authoritative boundary for programmatic callers)
- Add tests: validation guards, default isolation, --no-worktree
  skip, isolation-skipped warning, auto-detect $BASE_BRANCH success
- Add loadRepoConfig to @archon/core mock in workflow tests
- Update docs: CLAUDE.md, cli-user-guide, configuration,
  authoring-workflows, worktree-orchestration, README, cli.md rule
  — all updated for default isolation, archon/ prefix, optional
  baseBranch with auto-detection

* refactor: simplify isolation branch logic and fix log naming

- Split shouldIsolate into wantsIsolation + codebase check to
  eliminate redundant double-check of codebase
- Simplify else-if chain: use wantsIsolation instead of re-testing
  already-false conditions
- Deduplicate isolation-skipped warning messages
- Fix log event: base_branch.auto_detect_failed →
  workflow.base_branch_auto_detect_failed (project naming convention)

* fix: fail fast when isolation cannot be created instead of silent fallback

When the user hasn't opted out with --no-worktree, failing to create
a worktree (DB error or not in a git repo) now throws instead of
silently running in the live checkout. This prevents AI from making
unprotected changes to the working tree.

* chore: Auto-commit workflow artifacts (archon-assist)
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.

1 participant