Conversation
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>
WalkthroughStandardizes 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
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
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
Estimated code review effort🎯 4 (Complex) | ⏱️ ~75 minutes Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests
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. Comment |
There was a problem hiding this comment.
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 cachessetQueriesData 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 uploadsSame 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
textfor 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.
actis 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.
detailsisn’t part ofProgressResponse(per types). Drop it or extend the type; otherwise TS strict builds will complain.- details: {}, + // no extra fields- details: { result: "success" }, + // no extra fieldsAlso applies to: 82-87
140-157: ActiveOperationsResponse mocks missing required fields.Add
countandtimestampto 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
useSmartPollingsorefetchIntervalbecomesfalsewhen 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 === 404orerror.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
useSmartPollingso 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: Removeanyand typeuseQueriesresults.Avoid explicit
anyin 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. Preferundefined(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
useQueryfor 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 staleTimeReplace 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 titlenew 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: Avoidany; update tags with proper typingUse the typed
tags?: string[]on KnowledgeItem; removeas 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 crawlEnsures 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
📒 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.tsarchon-ui-main/src/features/knowledge/types/knowledge.tsarchon-ui-main/src/features/knowledge/views/KnowledgeView.tsxarchon-ui-main/src/features/progress/components/KnowledgeCardProgress.tsxarchon-ui-main/src/features/progress/components/CrawlingProgress.tsxarchon-ui-main/src/features/mcp/hooks/useMcpQueries.tsarchon-ui-main/src/features/knowledge/components/KnowledgeList.tsxarchon-ui-main/src/features/projects/hooks/tests/useProjectQueries.test.tsarchon-ui-main/src/features/projects/tasks/hooks/index.tsarchon-ui-main/src/features/shared/queryPatterns.tsarchon-ui-main/src/features/progress/services/progressService.tsarchon-ui-main/src/features/knowledge/components/KnowledgeCard.tsxarchon-ui-main/src/features/projects/views/ProjectsView.tsxarchon-ui-main/src/features/projects/tasks/hooks/useTaskQueries.tsarchon-ui-main/src/features/projects/tasks/hooks/tests/useTaskQueries.test.tsarchon-ui-main/src/features/progress/hooks/useProgressQueries.tsarchon-ui-main/src/features/projects/hooks/useProjectQueries.tsarchon-ui-main/src/features/projects/documents/hooks/useDocumentQueries.tsarchon-ui-main/src/features/knowledge/hooks/useKnowledgeQueries.tsarchon-ui-main/src/features/knowledge/hooks/tests/useKnowledgeQueries.test.tsarchon-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.tsarchon-ui-main/src/features/knowledge/types/knowledge.tsarchon-ui-main/src/features/knowledge/views/KnowledgeView.tsxarchon-ui-main/src/features/progress/components/KnowledgeCardProgress.tsxarchon-ui-main/src/features/progress/components/CrawlingProgress.tsxarchon-ui-main/src/features/mcp/hooks/useMcpQueries.tsarchon-ui-main/src/features/knowledge/components/KnowledgeList.tsxarchon-ui-main/src/features/projects/hooks/tests/useProjectQueries.test.tsarchon-ui-main/src/features/projects/tasks/hooks/index.tsarchon-ui-main/src/features/shared/queryPatterns.tsarchon-ui-main/src/features/progress/services/progressService.tsarchon-ui-main/src/features/knowledge/components/KnowledgeCard.tsxarchon-ui-main/src/features/projects/views/ProjectsView.tsxarchon-ui-main/src/features/projects/tasks/hooks/useTaskQueries.tsarchon-ui-main/src/features/projects/tasks/hooks/tests/useTaskQueries.test.tsarchon-ui-main/src/features/progress/hooks/useProgressQueries.tsarchon-ui-main/src/features/projects/hooks/useProjectQueries.tsarchon-ui-main/src/features/projects/documents/hooks/useDocumentQueries.tsarchon-ui-main/src/features/knowledge/hooks/useKnowledgeQueries.tsarchon-ui-main/src/features/knowledge/hooks/tests/useKnowledgeQueries.test.tsarchon-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.tsarchon-ui-main/src/features/knowledge/types/knowledge.tsarchon-ui-main/src/features/knowledge/views/KnowledgeView.tsxarchon-ui-main/src/features/progress/components/KnowledgeCardProgress.tsxarchon-ui-main/src/features/progress/components/CrawlingProgress.tsxarchon-ui-main/src/features/mcp/hooks/useMcpQueries.tsarchon-ui-main/src/features/knowledge/components/KnowledgeList.tsxarchon-ui-main/src/features/projects/hooks/tests/useProjectQueries.test.tsarchon-ui-main/src/features/projects/tasks/hooks/index.tsarchon-ui-main/src/features/shared/queryPatterns.tsarchon-ui-main/src/features/progress/services/progressService.tsarchon-ui-main/src/features/knowledge/components/KnowledgeCard.tsxarchon-ui-main/src/features/projects/views/ProjectsView.tsxarchon-ui-main/src/features/projects/tasks/hooks/useTaskQueries.tsarchon-ui-main/src/features/projects/tasks/hooks/tests/useTaskQueries.test.tsarchon-ui-main/src/features/progress/hooks/useProgressQueries.tsarchon-ui-main/src/features/projects/hooks/useProjectQueries.tsarchon-ui-main/src/features/projects/documents/hooks/useDocumentQueries.tsarchon-ui-main/src/features/knowledge/hooks/useKnowledgeQueries.tsarchon-ui-main/src/features/knowledge/hooks/tests/useKnowledgeQueries.test.tsarchon-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.tsarchon-ui-main/src/features/projects/hooks/tests/useProjectQueries.test.tsarchon-ui-main/src/features/projects/tasks/hooks/tests/useTaskQueries.test.tsarchon-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.tsarchon-ui-main/src/features/knowledge/views/KnowledgeView.tsxarchon-ui-main/src/features/progress/components/KnowledgeCardProgress.tsxarchon-ui-main/src/features/progress/components/CrawlingProgress.tsxarchon-ui-main/src/features/projects/hooks/tests/useProjectQueries.test.tsarchon-ui-main/src/features/projects/tasks/hooks/index.tsarchon-ui-main/src/features/progress/services/progressService.tsarchon-ui-main/src/features/projects/views/ProjectsView.tsxarchon-ui-main/src/features/projects/tasks/hooks/useTaskQueries.tsarchon-ui-main/src/features/projects/tasks/hooks/tests/useTaskQueries.test.tsarchon-ui-main/src/features/progress/hooks/useProgressQueries.tsarchon-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.tsarchon-ui-main/src/features/knowledge/views/KnowledgeView.tsxarchon-ui-main/src/features/progress/components/KnowledgeCardProgress.tsxarchon-ui-main/src/features/progress/components/CrawlingProgress.tsxarchon-ui-main/src/features/mcp/hooks/useMcpQueries.tsarchon-ui-main/src/features/projects/hooks/tests/useProjectQueries.test.tsarchon-ui-main/src/features/shared/queryPatterns.tsPRPs/ai_docs/QUERY_PATTERNS.mdarchon-ui-main/src/features/projects/views/ProjectsView.tsxarchon-ui-main/src/features/projects/tasks/hooks/useTaskQueries.tsarchon-ui-main/src/features/projects/tasks/hooks/tests/useTaskQueries.test.tsarchon-ui-main/src/features/progress/hooks/useProgressQueries.tsarchon-ui-main/src/features/projects/hooks/useProjectQueries.tsarchon-ui-main/src/features/projects/documents/hooks/useDocumentQueries.tsarchon-ui-main/src/features/knowledge/hooks/useKnowledgeQueries.tsarchon-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.tsarchon-ui-main/src/features/progress/components/CrawlingProgress.tsxarchon-ui-main/src/features/progress/services/progressService.tsarchon-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.tsarchon-ui-main/src/features/progress/components/CrawlingProgress.tsxarchon-ui-main/src/features/progress/services/progressService.tsarchon-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.tsarchon-ui-main/src/features/mcp/hooks/useMcpQueries.tsarchon-ui-main/src/features/shared/queryPatterns.tsPRPs/ai_docs/QUERY_PATTERNS.mdarchon-ui-main/src/features/projects/views/ProjectsView.tsxarchon-ui-main/src/features/projects/tasks/hooks/useTaskQueries.tsarchon-ui-main/src/features/progress/hooks/useProgressQueries.tsarchon-ui-main/src/features/projects/hooks/useProjectQueries.tsarchon-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.tsarchon-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.tsarchon-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.tsPRPs/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.tsPRPs/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.tsxarchon-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 reintroducedprogressService 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/activefollow 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)andfeatures(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 aProjectdirectly, replaceresponse.projectwithresponse.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 goodGood alignment with the shared pattern and stale time standardization.
- 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>
There was a problem hiding this comment.
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 branchReplicate 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 PUTServer 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
useSmartPollingcurrently 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 detectionThe “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 keysAdd
exact: trueto 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
useCrawlProgressPollingreimplements 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 renderMinor: 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)isreadonly string[]already assignable toQueryKey. 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
RefetchIntervalFunctionfor 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 TaskAssigneeThis 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 TaskAssigneeThis 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 primitivesImport 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 helperThis 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 utilThere’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 utilsgetAssigneeStyles 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_pageAlso 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
📒 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.tsarchon-ui-main/src/features/knowledge/services/knowledgeService.tsarchon-ui-main/src/features/projects/tasks/types/task.tsarchon-ui-main/src/features/projects/tasks/schemas/index.tsarchon-ui-main/src/features/projects/tasks/components/TaskAssignee.tsxarchon-ui-main/src/features/projects/tasks/components/EditableTableCell.tsxarchon-ui-main/src/features/projects/tasks/components/TaskEditModal.tsxarchon-ui-main/src/features/ui/primitives/combobox.tsxarchon-ui-main/src/features/projects/tasks/hooks/useTaskQueries.tsarchon-ui-main/src/features/knowledge/hooks/useKnowledgeQueries.tsarchon-ui-main/src/features/progress/hooks/useProgressQueries.tsarchon-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.tsarchon-ui-main/src/features/knowledge/services/knowledgeService.tsarchon-ui-main/src/features/projects/tasks/types/task.tsarchon-ui-main/src/features/projects/tasks/schemas/index.tsarchon-ui-main/src/features/projects/tasks/components/TaskAssignee.tsxarchon-ui-main/src/features/projects/tasks/components/EditableTableCell.tsxarchon-ui-main/src/features/projects/tasks/components/TaskEditModal.tsxarchon-ui-main/src/features/ui/primitives/combobox.tsxarchon-ui-main/src/features/projects/tasks/hooks/useTaskQueries.tsarchon-ui-main/src/features/knowledge/hooks/useKnowledgeQueries.tsarchon-ui-main/src/features/progress/hooks/useProgressQueries.tsarchon-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.tspython/src/server/services/knowledge/knowledge_summary_service.pyarchon-ui-main/src/features/knowledge/services/knowledgeService.tspython/src/mcp_server/features/tasks/task_tools.pyarchon-ui-main/src/features/projects/tasks/types/task.tsarchon-ui-main/src/features/projects/tasks/schemas/index.tsarchon-ui-main/src/features/projects/tasks/components/TaskAssignee.tsxarchon-ui-main/src/features/projects/tasks/components/EditableTableCell.tsxarchon-ui-main/src/features/projects/tasks/components/TaskEditModal.tsxarchon-ui-main/src/features/ui/primitives/combobox.tsxarchon-ui-main/src/features/projects/tasks/hooks/useTaskQueries.tsarchon-ui-main/src/features/knowledge/hooks/useKnowledgeQueries.tsarchon-ui-main/src/features/progress/hooks/useProgressQueries.tsarchon-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.pypython/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.tsarchon-ui-main/src/features/projects/tasks/hooks/useTaskQueries.tsarchon-ui-main/src/features/knowledge/hooks/useKnowledgeQueries.tsarchon-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.tsarchon-ui-main/src/features/knowledge/hooks/useKnowledgeQueries.tsarchon-ui-main/src/features/progress/hooks/useProgressQueries.tsarchon-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.tsarchon-ui-main/src/features/knowledge/hooks/useKnowledgeQueries.tsarchon-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.tsarchon-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.tsarchon-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)
| // 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} | ||
| /> | ||
| ); | ||
| } |
There was a problem hiding this comment.
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>
There was a problem hiding this comment.
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 usingassigneequery param.Verified: server routes/services, migration, docs and tests use/query
assigneeand honorinclude_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
📒 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>
There was a problem hiding this comment.
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 anassertNeverhelper.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 touseSmartPollingto match v5 patterns.Docs still mention
usePolling; project guidance and PR objectives standardize onuseSmartPolling.-### 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` hooksarchon-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/undefinedor 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 tasksarchon-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 anyweakens 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
📒 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.tsarchon-ui-main/src/features/ui/hooks/useSmartPolling.tsarchon-ui-main/src/features/projects/tasks/utils/task-styles.tsxarchon-ui-main/src/features/knowledge/hooks/useKnowledgeQueries.tsarchon-ui-main/src/features/progress/hooks/useProgressQueries.tsarchon-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.tsarchon-ui-main/src/features/ui/hooks/useSmartPolling.tsarchon-ui-main/src/features/projects/tasks/utils/task-styles.tsxarchon-ui-main/src/features/knowledge/hooks/useKnowledgeQueries.tsarchon-ui-main/src/features/progress/hooks/useProgressQueries.tsarchon-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.tsarchon-ui-main/src/features/ui/hooks/useSmartPolling.tsarchon-ui-main/src/features/projects/tasks/utils/task-styles.tsxarchon-ui-main/src/features/knowledge/hooks/useKnowledgeQueries.tsarchon-ui-main/src/features/progress/hooks/useProgressQueries.tsarchon-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.tsarchon-ui-main/src/features/knowledge/hooks/useKnowledgeQueries.tsarchon-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.tsarchon-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.tsarchon-ui-main/src/features/knowledge/hooks/useKnowledgeQueries.tsarchon-ui-main/src/features/progress/hooks/useProgressQueries.tsarchon-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.tsarchon-ui-main/src/features/knowledge/hooks/useKnowledgeQueries.tsarchon-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.tsarchon-ui-main/src/features/knowledge/hooks/useKnowledgeQueries.tsarchon-ui-main/src/features/progress/hooks/useProgressQueries.tsarchon-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.tsarchon-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.tsarchon-ui-main/src/features/progress/hooks/useProgressQueries.tsarchon-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.tsarchon-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 flexibleAssignee = 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
taskKeysfactory 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), andactive()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()andcodeExamples(), and providessummariesPrefix()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.
| // 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 |
There was a problem hiding this comment.
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:
- Recommended: Update all relevant summary caches based on filter matching
- Remove optimistic updates entirely if proper implementation is complex
- 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.
| // 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 |
There was a problem hiding this comment.
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).
…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>
) * 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)
…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)
…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)
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
knowledge/progressto top-level/features/progressDISABLED_QUERY_KEY, comprehensiveSTALE_TIMES)Type of Change
Affected Services
Testing
Test Evidence
Checklist
Breaking Changes
Cache Reset Required
Import Path Changes
knowledge/progress→progressRemoved Methods
projectKeys.tasks()andprojectKeys.taskCounts()removedknowledgeKeys.summary()replaced withknowledgeKeys.summaries()knowledgeKeys.details()removed (usedetail())Implementation Details
Query Key Factories Standardized (31 files changed)
Shared Patterns Implementation
Success Metrics Achieved
Additional Notes
Documentation
Created comprehensive
QUERY_PATTERNS.mdguide including:Performance Impact
Related PRs
PRP Reference: PRPs/completed/story_phase_2_query_keys_standardization.md
Summary by CodeRabbit