Skip to content

Conversation

@frankbria
Copy link
Owner

@frankbria frankbria commented Jan 12, 2026

Summary

Fixes #248 - Tasks stuck in "pending" state with "Assigned to: Unassigned" for late-joining users

  • Fix LeadAgent to set assigned_to field when assigning tasks (root cause of display bug)
  • Add manual trigger endpoint POST /api/projects/{id}/tasks/assign
  • Add "Assign Tasks" button to TaskList component (shows only when needed)

Changes

File Description
codeframe/agents/lead_agent.py Set assigned_to before status update in _assign_and_execute_task()
codeframe/ui/routers/tasks.py Add assign_pending_tasks endpoint and TaskAssignmentResponse model
web-ui/src/lib/api.ts Add tasksApi.assignPending() method
web-ui/src/components/TaskList.tsx Add contextual "Assign Tasks" banner with button
tests/ui/test_assign_pending_tasks.py New: 9 unit tests for endpoint
tests/integration/test_multi_agent_execution.py New: 2 tests for assigned_to fix

Root Cause Analysis

The original _assign_and_execute_task() never set task.assigned_to, so the UI correctly showed "Unassigned" even during active execution. This was a pre-existing bug that the original plan didn't identify.

Test plan

  • Backend tests: 47 tests passing
  • Frontend tests: 1563 tests passing
  • Frontend build: No TypeScript errors
  • Manual: Approve tasks → verify agents appear with correct assignment
  • Manual: Refresh page with pending tasks → click "Assign Tasks" button

Summary by CodeRabbit

  • New Features

    • API endpoint to manually trigger assignment of pending unassigned tasks; returns pending count and status message.
    • UI banner shows pending-unassigned task count with a button to trigger assignment; includes loading/error states.
    • Front-end API method to call the assignment endpoint.
  • Enhancements

    • Assignment now records the responsible agent before the task status advances for more accurate UI reflection.
    • Endpoint logs scheduling, in-progress, and missing API key scenarios.
  • Tests

    • Added integration and UI tests covering assignment behavior, ordering, responses, and edge cases.

✏️ Tip: You can customize this high-level summary in your review settings.

Fixes Issue #248 where tasks remained stuck in "pending" state with
"Assigned to: Unassigned" for late-joining users or after execution failures.

Changes:
- Fix LeadAgent._assign_and_execute_task() to set assigned_to field
  before status transitions (root cause of display bug)
- Add POST /api/projects/{id}/tasks/assign endpoint for manual trigger
- Add tasksApi.assignPending() frontend API client method
- Add "Assign Tasks" banner to TaskList when pending unassigned tasks exist
- Add comprehensive tests for all new functionality

The button appears contextually only when tasks are stuck, and auto-hides
when tasks get assigned via WebSocket updates.
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 12, 2026

Walkthrough

Adds a project-scoped POST endpoint to trigger assignment of pending unassigned tasks, updates LeadAgent to persist assigned_to before setting in_progress, integrates frontend assignment UI/API, and adds integration and endpoint tests validating assignment ordering and behavior.

Changes

Cohort / File(s) Summary
Backend API Endpoint
codeframe/ui/routers/tasks.py
New POST /api/projects/{project_id}/tasks/assign and TaskAssignmentResponse model; validates project/phase/access, counts pending unassigned tasks, returns pending_count and message, and schedules background multi-agent execution when ANTHROPIC_API_KEY is present (logs if missing).
Agent Execution Logic
codeframe/agents/lead_agent.py
_assign_and_execute_task now writes assigned_to (agent_id) to the task before updating status to in_progress, ensuring assignment is persisted prior to status change.
Frontend API Client
web-ui/src/lib/api.ts
Adds tasksApi.assignPending(projectId) which POSTs to /api/projects/${projectId}/tasks/assign and returns { success, pending_count, message }.
Frontend UI Component
web-ui/src/components/TaskList.tsx
Adds assignment UI state (isAssigning, assignmentError), computes pendingUnassignedCount/hasPendingUnassigned, shows a banner with an "Assign Tasks" button that calls the new API and reflects loading/error/in-progress states.
Integration Tests (Agent behavior)
tests/integration/test_multi_agent_execution.py
New tests (TestAssignAndExecuteTaskAssignedTo) asserting _assign_and_execute_task sets assigned_to and that the DB write for assigned_to occurs no later than the status update to in_progress; uses mocked AgentPoolManager/agents and captures DB update call order.
API Route Tests
tests/ui/test_assign_pending_tasks.py
New tests covering assign endpoint: successful scheduling, no-op when no pending tasks, wrong phase (400), project not found (404), access denied (403), missing ANTHROPIC_API_KEY behavior (logs, no scheduling), correct pending-unassigned counting, and response model validation.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Frontend as Web UI (TaskList)
    participant API as Backend API
    participant DB as Database
    participant BG as Background Task Runner
    participant LeadAgent as Lead Agent

    User->>Frontend: Click "Assign Tasks" button
    Frontend->>API: POST /api/projects/{id}/tasks/assign
    API->>DB: Validate project, user, phase
    API->>DB: Count pending unassigned tasks
    alt pending tasks exist and no execution in progress
        API->>BG: Schedule start_development_execution (background)
        API->>Frontend: Return success + pending_count + message
        BG->>LeadAgent: start_development_execution
        LeadAgent->>DB: Update task -> set assigned_to = agent_id
        LeadAgent->>DB: Update task -> set status = in_progress
        LeadAgent->>DB: Continue task execution...
    else no pending tasks
        API->>Frontend: Return success (pending_count = 0)
    end
    Frontend->>Frontend: Update banner/UI state
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐇 I nudged the queue with a tiny paw,
I wrote their names before the race began,
Pending no more, they hopped into line,
Agents sprang forth with tasks in hand,
Hop—assignments hum, and work goes on.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding an Assign Tasks button for stuck pending tasks, which is the primary feature introduced in this PR.
Linked Issues check ✅ Passed The PR fully addresses issue #248 by implementing a manual assignment trigger button, fixing the root cause (assigned_to not being set), and enabling task assignment when stuck in Pending state.
Out of Scope Changes check ✅ Passed All changes are directly scoped to fixing issue #248: the lead_agent fix addresses the root cause, the endpoint enables manual assignment, and the UI provides the user-facing control—no unrelated changes detected.
Docstring Coverage ✅ Passed Docstring coverage is 84.62% which is sufficient. The required threshold is 80.00%.

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

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/248-assign-tasks-button

📜 Recent review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7c8b856 and 5c06e22.

📒 Files selected for processing (2)
  • codeframe/ui/routers/tasks.py
  • tests/ui/test_assign_pending_tasks.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/ui/test_assign_pending_tasks.py
🧰 Additional context used
📓 Path-based instructions (1)
codeframe/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

codeframe/**/*.py: Use Python 3.11+ for backend development
Use FastAPI framework for backend API development
Use SQLite with async support (aiosqlite) for database operations
Use tiktoken for token counting
Run linting with ruff check .
Import and use domain-specific repositories from codeframe/persistence/repositories/ for data access instead of direct database calls

Files:

  • codeframe/ui/routers/tasks.py
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Backend Unit Tests
  • GitHub Check: Frontend Unit Tests
  • GitHub Check: opencode-review
  • GitHub Check: E2E Smoke Tests (Chromium)
🔇 Additional comments (4)
codeframe/ui/routers/tasks.py (4)

380-384: LGTM!

The response model is well-structured and consistent with the existing TaskApprovalResponse pattern in this file.


387-436: LGTM!

The endpoint signature and validation logic follows the established patterns in this file. The authorization check, project existence verification, and phase validation are correctly implemented.


438-473: LGTM with minor observation.

The task filtering logic and concurrent execution check are well-implemented. Including ASSIGNED status in the execution check (line 462) is a good safeguard against race conditions between assignment and execution start.

Note: There's an inherent TOCTOU (time-of-check-to-time-of-use) window between checking task states here and the background task starting execution. However, since start_development_execution will re-query tasks via LeadAgent.start_multi_agent_execution(), this is acceptable—duplicate triggers will be benign as the lead agent's own logic should handle already-assigned tasks.


475-500: LGTM!

The API key validation correctly returns success=False when misconfigured (aligning with PR objectives), and the background task scheduling follows the same pattern as the existing approve_tasks endpoint.


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

@macroscopeapp
Copy link

macroscopeapp bot commented Jan 12, 2026

Add Assign Tasks button in web-ui/src/components/TaskList.tsx and POST tasks.assign_pending_tasks endpoint to assign stuck pending tasks when project phase is active and no tasks are ASSIGNED or IN_PROGRESS

Introduce POST /api/projects/{project_id}/tasks/assign with tasks.TaskAssignmentResponse and wire it to TaskList UI to trigger background assignment only for pending unassigned tasks and require ANTHROPIC_API_KEY. Update LeadAgent._assign_and_execute_task behavior and add integration/UI tests.

📍Where to Start

Start with the handler tasks.assign_pending_tasks in tasks.py, then review the UI integration in TaskList.tsx.


Macroscope summarized 5c06e22.


// Assignment state (Issue #248 fix)
const [isAssigning, setIsAssigning] = useState(false);
const [assignmentError, setAssignmentError] = useState<string | null>(null);
Copy link

Choose a reason for hiding this comment

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

assignmentError persists across banner hide/show, so a past error is shown when new pending tasks appear. Consider resetting assignmentError when hasPendingUnassigned changes (e.g., clear on hide or when it becomes true) so the banner starts clean.

🚀 Want me to fix this? Reply ex: "fix it for me".

}
// Success - the WebSocket will update the task list as agents are assigned
} catch (error) {
const errorMessage = error instanceof Error ? error.message : 'Failed to assign tasks';
Copy link

Choose a reason for hiding this comment

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

handleAssignTasks surfaces generic error.message and misses server messages from error.response?.data?.message. Consider preferring the response message (with a safe runtime check) so users see meaningful errors.

Suggested change
const errorMessage = error instanceof Error ? error.message : 'Failed to assign tasks';
const errorMessage = ((error as any)?.response?.data?.message as string) ?? (error instanceof Error ? error.message : 'Failed to assign tasks');

🚀 Want me to fix this? Reply ex: "fix it for me".

@github-actions
Copy link
Contributor

Code Review: PR #250 - Assign Tasks Button Fix

Overall assessment: LGTM with 1 blocking issue and a few suggestions

✅ Strengths

  1. Root cause fix is correct - Setting assigned_to before status change in lead_agent.py:1874-1875 ensures UI displays assignment immediately
  2. Good test coverage - 9 unit tests + 2 integration tests covering edge cases
  3. Proper authorization - All required checks (404, 403, 400) in place
  4. Clean frontend implementation - Follows existing patterns with memo/useCallback, good state management
  5. Type safety - All TypeScript types properly defined

🚫 Blocking Issue

tasks.py:455-467 - Misleading success response when API key missing

When ANTHROPIC_API_KEY is not configured, the endpoint returns success=True with message "Assignment started for N task(s)" but actually does nothing. This will confuse users.

# Current behavior - misleading:
if api_key:
    background_tasks.add_task(...)
    logger.info(f"✅ Scheduled task assignment...")
else:
    logger.warning(f"⚠️  ANTHROPIC_API_KEY not configured...")  # Nothing happens!

return TaskAssignmentResponse(
    success=True,  # ❌ Misleading!
    pending_count=pending_count,
    message=f"Assignment started for {pending_count} pending task(s)."  # ❌ False!
)

Suggested fix:

if api_key:
    background_tasks.add_task(...)
    logger.info(f"✅ Scheduled task assignment...")
    return TaskAssignmentResponse(
        success=True,
        pending_count=pending_count,
        message=f"Assignment started for {pending_count} pending task(s)."
    )
else:
    logger.warning(f"⚠️  ANTHROPIC_API_KEY not configured...")
    return TaskAssignmentResponse(
        success=False,
        pending_count=pending_count,
        message="Cannot assign tasks: ANTHROPIC_API_KEY not configured"
    )

📝 Suggestions

1. Prevent duplicate assignment triggers (Low priority)

Currently, a user could click "Assign Tasks" multiple times before the first execution completes, triggering multiple background executions. Consider adding a flag to track if assignment is in progress:

# In assign_pending_tasks():
# Check if there are already tasks in assigned or in_progress state
executing_or_assigned = [
    t for t in tasks 
    if t.status in [TaskStatus.ASSIGNED, TaskStatus.IN_PROGRESS]
]
if executing_or_assigned:
    return TaskAssignmentResponse(
        success=False,
        pending_count=pending_count,
        message="Assignment already in progress. Wait for current tasks to complete."
    )

2. Frontend: Consider optimistic update (Nice to have)

The frontend relies on WebSocket updates to refresh task status. Consider an optimistic update to show "Assigning..." status immediately on pending tasks for better UX:

// After calling assignPending(), temporarily mark tasks as assigning
const handleAssignTasks = useCallback(async () => {
  setIsAssigning(true);
  setAssignmentError(null);
  try {
    const response = await tasksApi.assignPending(projectId);
    if (response.data.success) {
      // Optional: Mark pending tasks as "assigning" locally for immediate feedback
      // WebSocket will eventually update with actual agent IDs
    }
  } ...
}, [projectId]);

3. Add logging for edge case (Debugging)

In tasks.py:446-451, when pending_count == 0, consider adding debug logging to help diagnose why tasks might appear stuck:

if pending_count == 0:
    logger.debug(
        f"assign_pending_tasks called for project {project_id} but found 0 pending unassigned tasks. "
        f"Total tasks: {len(tasks)}, statuses: {[t.status for t in tasks]}"
    )
    return TaskAssignmentResponse(...)

✅ Code Quality Notes

  • Backend: Follows FastAPI patterns, proper use of Depends, clean docstrings
  • Frontend: Follows React best practices with memo/useCallback/useMemo
  • Testing: Good use of pytest fixtures, comprehensive coverage
  • Security: Authorization checks in place (get_current_user, user_has_project_access)

Test Coverage

✅ Unit tests cover:

  • Success case with pending tasks
  • No pending tasks
  • Wrong phase (400)
  • Project not found (404)
  • Access denied (403)
  • Missing API key
  • Correct filtering (pending AND unassigned)
  • Response model structure
  • Function signature

✅ Integration tests verify:

  • assigned_to field is populated correctly
  • Assignment happens before status changes to in_progress

Verdict: Fix the blocking issue and this is ready to merge. The suggestions are optional improvements for future iterations.

@github-actions
Copy link
Contributor

I've reviewed PR #250 and posted a detailed code review as a comment on the PR.

Review Summary

Overall Assessment: LGTM with 1 blocking issue

Blocking Issue Found

tasks.py:455-467 - When ANTHROPIC_API_KEY is missing, the endpoint returns success=True with message "Assignment started..." but actually does nothing. This is misleading to users.

Key Strengths

  • Root cause fix in lead_agent.py is correct
  • Comprehensive test coverage (9 unit tests + 2 integration tests)
  • Proper authentication and authorization checks
  • Clean frontend implementation following React best practices

Suggestions

  1. Return success=False when API key is missing
  2. Consider preventing duplicate assignment triggers
  3. Add debug logging for edge case (0 pending tasks)
  4. Consider optimistic UI updates

The PR is well-structured with good test coverage. Fixing the blocking issue about the misleading success response when the API key is missing would make this ready to merge.

New%20session%20-%202026-01-12T00%3A45%3A21.162Z
opencode session  |  github run

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In @codeframe/ui/routers/tasks.py:
- Around line 453-473: The response always indicates success even when
ANTHROPIC_API_KEY is missing; update the logic around api_key and the
TaskAssignmentResponse so that when api_key is falsy the endpoint returns
success=False (or an error code) and a clear message like "ANTHROPIC_API_KEY not
configured - assignment not started" instead of "Assignment started...";
concretely, in the block using api_key and background_tasks (references:
api_key, start_development_execution, TaskAssignmentResponse, logger),
move/modify the return to occur after the api_key check so the success and
message reflect whether background_tasks.add_task was called (return
success=True only when api_key truthy and task scheduled, otherwise return
success=False with the warning message).
🧹 Nitpick comments (3)
codeframe/agents/lead_agent.py (1)

1873-1876: Consider combining into a single atomic update.

The fix correctly sets assigned_to before the status change, which addresses Issue #248. However, two separate update_task calls introduce a race window where another process could read inconsistent state between the updates. Combining them into a single call improves atomicity and reduces database round-trips.

♻️ Suggested improvement
-            # Update task with assigned agent and status (Issue #248 fix)
-            # Set assigned_to BEFORE status change so UI shows assignment immediately
-            self.db.update_task(task.id, {"assigned_to": agent_id})
-            self.db.update_task(task.id, {"status": "in_progress"})
+            # Update task with assigned agent and status atomically (Issue #248 fix)
+            # Both fields updated together so UI shows assignment immediately
+            self.db.update_task(task.id, {"assigned_to": agent_id, "status": "in_progress"})
web-ui/src/components/TaskList.tsx (1)

221-233: Consider combining derived state into a single memo.

Both hasPendingUnassigned and pendingUnassignedCount iterate over projectTasks with the same filter logic. Combining them reduces redundant iterations.

♻️ Suggested improvement
-  // Check if there are pending unassigned tasks (Issue #248 fix)
-  const hasPendingUnassigned = useMemo(() => {
-    return projectTasks.some(
-      (task) => task.status === 'pending' && !task.agent_id
-    );
-  }, [projectTasks]);
-
-  // Count of pending unassigned tasks
-  const pendingUnassignedCount = useMemo(() => {
-    return projectTasks.filter(
-      (task) => task.status === 'pending' && !task.agent_id
-    ).length;
-  }, [projectTasks]);
+  // Pending unassigned task stats (Issue #248 fix)
+  const { hasPendingUnassigned, pendingUnassignedCount } = useMemo(() => {
+    const pendingUnassigned = projectTasks.filter(
+      (task) => task.status === 'pending' && !task.agent_id
+    );
+    return {
+      hasPendingUnassigned: pendingUnassigned.length > 0,
+      pendingUnassignedCount: pendingUnassigned.length,
+    };
+  }, [projectTasks]);
tests/integration/test_multi_agent_execution.py (1)

724-783: Make get_or_create_agent mocking argument-driven (not call-order) to avoid brittle tests.
Right now the “first call worker / second call review” assumption will break if _assign_and_execute_task() adds one more get_or_create_agent() call internally.

Proposed change
-                # Also mock the review agent to avoid review step
-                with patch.object(lead_agent.agent_pool_manager, "get_or_create_agent") as mock_get_agent:
-                    # First call returns worker agent, second call returns review agent
-                    mock_get_agent.side_effect = ["test-agent-001", "review-agent-001"]
+                # Mock worker vs review agent selection based on requested agent type (more robust than call-order)
+                def get_agent_side_effect(agent_type, *args, **kwargs):
+                    return "review-agent-001" if agent_type == "review" else "test-agent-001"
+
+                mock_pool.get_or_create_agent.side_effect = get_agent_side_effect
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ddd386f and 46947ca.

📒 Files selected for processing (6)
  • codeframe/agents/lead_agent.py
  • codeframe/ui/routers/tasks.py
  • tests/integration/test_multi_agent_execution.py
  • tests/ui/test_assign_pending_tasks.py
  • web-ui/src/components/TaskList.tsx
  • web-ui/src/lib/api.ts
🧰 Additional context used
📓 Path-based instructions (4)
web-ui/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

web-ui/src/**/*.{ts,tsx}: Use TypeScript 5.3+ for frontend development
Use React 18 and Next.js 14 for frontend development
Use Tailwind CSS for styling with Nova design system template
Use shadcn/ui components from @/components/ui/ for UI elements
Use Hugeicons (@hugeicons/react) for all icons, never mix with lucide-react
Use Nova color palette variables (bg-card, text-foreground, etc.) instead of hardcoded color values
Use cn() utility for conditional CSS classes in React components
Use process.env.NEXT_PUBLIC_API_URL with fallback to http://localhost:8080 for API endpoint configuration
Include auth token as query parameter in WebSocket connections (?token=TOKEN)
Store auth tokens in localStorage with key 'auth_token' and include token in API requests via Authorization header

Files:

  • web-ui/src/lib/api.ts
  • web-ui/src/components/TaskList.tsx
web-ui/src/lib/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Implement WebSocket automatic reconnection with exponential backoff (1s → 30s) and full state resync

Files:

  • web-ui/src/lib/api.ts
codeframe/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

codeframe/**/*.py: Use Python 3.11+ for backend development
Use FastAPI framework for backend API development
Use SQLite with async support (aiosqlite) for database operations
Use tiktoken for token counting
Run linting with ruff check .
Import and use domain-specific repositories from codeframe/persistence/repositories/ for data access instead of direct database calls

Files:

  • codeframe/agents/lead_agent.py
  • codeframe/ui/routers/tasks.py
web-ui/src/components/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

web-ui/src/components/**/*.{ts,tsx}: Use React Context with useReducer for centralized state management in Dashboard
Wrap AgentStateProvider with ErrorBoundary component for graceful error handling
Use React.memo on Dashboard sub-components and useMemo for derived state to optimize performance

Files:

  • web-ui/src/components/TaskList.tsx
🧠 Learnings (5)
📚 Learning: 2025-12-17T19:21:40.014Z
Learnt from: frankbria
Repo: frankbria/codeframe PR: 128
File: tests/agents/test_bottleneck_detection.py:486-500
Timestamp: 2025-12-17T19:21:40.014Z
Learning: In tests/agents/test_bottleneck_detection.py, test_skip_agents_below_threshold should be async and mock _get_agent_workload to return workload below AGENT_OVERLOAD_THRESHOLD (5) while providing non-empty tasks list to prevent early return in detect_bottlenecks().

Applied to files:

  • tests/integration/test_multi_agent_execution.py
📚 Learning: 2026-01-11T23:33:31.883Z
Learnt from: CR
Repo: frankbria/codeframe PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-11T23:33:31.883Z
Learning: Applies to web-ui/src/components/**/*.{ts,tsx} : Wrap AgentStateProvider with ErrorBoundary component for graceful error handling

Applied to files:

  • web-ui/src/components/TaskList.tsx
📚 Learning: 2026-01-11T23:33:31.883Z
Learnt from: CR
Repo: frankbria/codeframe PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-11T23:33:31.883Z
Learning: Applies to web-ui/src/reducers/**/*.{ts,tsx} : Use useReducer with 13+ action types for agent state management; implement timestamp conflict resolution with last-write-wins strategy

Applied to files:

  • web-ui/src/components/TaskList.tsx
📚 Learning: 2025-11-25T19:08:37.203Z
Learnt from: CR
Repo: frankbria/codeframe PR: 0
File: docs/CLAUDE.md:0-0
Timestamp: 2025-11-25T19:08:37.203Z
Learning: Applies to docs/web-ui/src/**/*.{ts,tsx} : Use SWR for server state management and useState for local state in React

Applied to files:

  • web-ui/src/components/TaskList.tsx
📚 Learning: 2026-01-11T23:33:31.883Z
Learnt from: CR
Repo: frankbria/codeframe PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-11T23:33:31.883Z
Learning: Applies to web-ui/src/components/**/*.{ts,tsx} : Use React.memo on Dashboard sub-components and useMemo for derived state to optimize performance

Applied to files:

  • web-ui/src/components/TaskList.tsx
🧬 Code graph analysis (1)
web-ui/src/components/TaskList.tsx (1)
web-ui/src/lib/api.ts (1)
  • tasksApi (148-168)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: E2E Smoke Tests (Chromium)
  • GitHub Check: Macroscope - Correctness Check
  • GitHub Check: opencode-review
🔇 Additional comments (11)
web-ui/src/lib/api.ts (1)

153-167: LGTM!

The new assignPending method follows established patterns in this file. The response type matches TaskAssignmentResponse from the backend, and the JSDoc documentation clearly explains the purpose and usage.

web-ui/src/components/TaskList.tsx (3)

182-184: LGTM!

State management for the assignment flow is clean and follows React patterns. The separation of loading (isAssigning) and error (assignmentError) states enables good UX feedback.


236-251: LGTM!

The handler properly manages loading state, error handling, and cleanup via finally. Relying on WebSocket updates for task list refresh (rather than manual refetch) is the correct approach given the existing architecture.


301-327: LGTM!

The banner implementation follows the Nova design system with proper color variables, includes accessible disabled states, handles singular/plural grammar, and provides clear error feedback. Good use of data-testid attributes for testing.

codeframe/ui/routers/tasks.py (2)

380-384: LGTM!

The TaskAssignmentResponse model is well-defined and matches the frontend's expected response structure.


418-451: LGTM!

Validation logic follows established patterns in this file. The early return for zero pending tasks avoids unnecessary background task scheduling.

tests/ui/test_assign_pending_tasks.py (4)

17-27: LGTM!

Good fixture design that ensures deterministic tests by clearing the API key by default. Tests that need API key behavior explicitly set it via patch.dict.


60-182: LGTM!

Comprehensive test coverage for success and error paths. Tests properly verify both response values and side effects (background task scheduling).


184-217: Test correctly validates current behavior, but may need update.

This test validates the current implementation where success=True is returned even when the API key is missing. If the endpoint is updated to return success=False when the API key is not configured (as suggested in the tasks.py review), this test's assertion on line 210 will need to change to assert response.success is False.


219-277: LGTM!

Thorough test for counting logic with mixed task states. The response model and function signature tests provide good regression protection against accidental API changes.

tests/integration/test_multi_agent_execution.py (1)

827-897: The test assertion is already correct and resilient; the suggested changes are unnecessary.

The implementation at line 1876 uses a hard-coded string {"status": "in_progress"}, not an enum, and this matches the test's assertion. Checking for both TaskStatus.IN_PROGRESS.value and the string adds complexity without benefit. Additionally, assigned_to is updated only once per execution (line 1875), so capturing the "first" occurrence is defensive for a non-existent issue. The test as written correctly validates the execution order and handles the actual implementation behavior.

Likely an incorrect or invalid review comment.

Phase 1 fix for concurrent execution issue:
- Backend: Check for in_progress tasks before scheduling new execution
- Frontend: Disable button when tasks are already running
- Frontend: Show "Running..." state and updated message when execution active
- Add 2 new tests for execution blocking behavior
tasks = db.get_project_tasks(project_id)
pending_unassigned = [
t for t in tasks
if t.status == TaskStatus.PENDING and not t.assigned_to
Copy link

Choose a reason for hiding this comment

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

t.status may be a string, so comparing to TaskStatus members (TaskStatus.PENDING / TaskStatus.IN_PROGRESS) will fail and skip tasks. Consider normalizing t.status to a TaskStatus before filtering, or compare to .value if statuses are stored as strings.

🚀 Want me to fix this? Reply ex: "fix it for me".

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
web-ui/src/components/TaskList.tsx (1)

221-238: Consider combining hasPendingUnassigned and pendingUnassignedCount into a single memo.

Both memos iterate over projectTasks with the same filter condition. Combining them into one pass would avoid redundant iteration.

♻️ Suggested optimization
-  // Check if there are pending unassigned tasks (Issue #248 fix)
-  const hasPendingUnassigned = useMemo(() => {
-    return projectTasks.some(
-      (task) => task.status === 'pending' && !task.agent_id
-    );
-  }, [projectTasks]);
-
-  // Count of pending unassigned tasks
-  const pendingUnassignedCount = useMemo(() => {
-    return projectTasks.filter(
-      (task) => task.status === 'pending' && !task.agent_id
-    ).length;
-  }, [projectTasks]);
+  // Count and check for pending unassigned tasks (Issue #248 fix)
+  const pendingUnassignedCount = useMemo(() => {
+    return projectTasks.filter(
+      (task) => task.status === 'pending' && !task.agent_id
+    ).length;
+  }, [projectTasks]);
+
+  const hasPendingUnassigned = pendingUnassignedCount > 0;
tests/ui/test_assign_pending_tasks.py (1)

219-245: Test name and assertion may be misleading.

The test is named test_assign_pending_tasks_only_counts_unassigned, but it also implicitly tests the "blocked when in_progress" behavior due to the IN_PROGRESS task at line 230. The assertion at lines 243-244 checks for "in progress" in the message, which is about blocking, not counting.

Consider splitting this into two separate tests or renaming to clarify its scope.

♻️ Suggested clarification

Option 1: Remove the IN_PROGRESS task from this test to purely test counting:

         mock_db.get_project_tasks.return_value = [
             Task(id=1, project_id=1, title="Task 1", status=TaskStatus.PENDING, assigned_to=None),      # Count this
             Task(id=2, project_id=1, title="Task 2", status=TaskStatus.PENDING, assigned_to="agent-1"), # Already assigned
-            Task(id=3, project_id=1, title="Task 3", status=TaskStatus.IN_PROGRESS, assigned_to=None),  # Not pending
+            Task(id=3, project_id=1, title="Task 3", status=TaskStatus.COMPLETED, assigned_to="agent-1"),  # Not pending
         ]

Option 2: Rename the test to reflect its actual behavior, e.g., test_assign_pending_tasks_counts_unassigned_and_respects_in_progress.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 46947ca and 3cbdff5.

📒 Files selected for processing (3)
  • codeframe/ui/routers/tasks.py
  • tests/ui/test_assign_pending_tasks.py
  • web-ui/src/components/TaskList.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • codeframe/ui/routers/tasks.py
🧰 Additional context used
📓 Path-based instructions (2)
web-ui/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

web-ui/src/**/*.{ts,tsx}: Use TypeScript 5.3+ for frontend development
Use React 18 and Next.js 14 for frontend development
Use Tailwind CSS for styling with Nova design system template
Use shadcn/ui components from @/components/ui/ for UI elements
Use Hugeicons (@hugeicons/react) for all icons, never mix with lucide-react
Use Nova color palette variables (bg-card, text-foreground, etc.) instead of hardcoded color values
Use cn() utility for conditional CSS classes in React components
Use process.env.NEXT_PUBLIC_API_URL with fallback to http://localhost:8080 for API endpoint configuration
Include auth token as query parameter in WebSocket connections (?token=TOKEN)
Store auth tokens in localStorage with key 'auth_token' and include token in API requests via Authorization header

Files:

  • web-ui/src/components/TaskList.tsx
web-ui/src/components/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

web-ui/src/components/**/*.{ts,tsx}: Use React Context with useReducer for centralized state management in Dashboard
Wrap AgentStateProvider with ErrorBoundary component for graceful error handling
Use React.memo on Dashboard sub-components and useMemo for derived state to optimize performance

Files:

  • web-ui/src/components/TaskList.tsx
🧠 Learnings (4)
📚 Learning: 2026-01-11T23:33:31.883Z
Learnt from: CR
Repo: frankbria/codeframe PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-11T23:33:31.883Z
Learning: Applies to web-ui/src/components/**/*.{ts,tsx} : Wrap AgentStateProvider with ErrorBoundary component for graceful error handling

Applied to files:

  • web-ui/src/components/TaskList.tsx
📚 Learning: 2026-01-11T23:33:31.883Z
Learnt from: CR
Repo: frankbria/codeframe PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-11T23:33:31.883Z
Learning: Applies to web-ui/src/reducers/**/*.{ts,tsx} : Use useReducer with 13+ action types for agent state management; implement timestamp conflict resolution with last-write-wins strategy

Applied to files:

  • web-ui/src/components/TaskList.tsx
📚 Learning: 2025-11-25T19:08:37.203Z
Learnt from: CR
Repo: frankbria/codeframe PR: 0
File: docs/CLAUDE.md:0-0
Timestamp: 2025-11-25T19:08:37.203Z
Learning: Applies to docs/web-ui/src/**/*.{ts,tsx} : Use SWR for server state management and useState for local state in React

Applied to files:

  • web-ui/src/components/TaskList.tsx
📚 Learning: 2026-01-11T23:33:31.883Z
Learnt from: CR
Repo: frankbria/codeframe PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-11T23:33:31.883Z
Learning: Applies to web-ui/src/components/**/*.{ts,tsx} : Use React.memo on Dashboard sub-components and useMemo for derived state to optimize performance

Applied to files:

  • web-ui/src/components/TaskList.tsx
🧬 Code graph analysis (2)
web-ui/src/components/TaskList.tsx (1)
web-ui/src/lib/api.ts (1)
  • tasksApi (148-168)
tests/ui/test_assign_pending_tasks.py (1)
codeframe/ui/routers/tasks.py (2)
  • assign_pending_tasks (388-486)
  • TaskAssignmentResponse (380-384)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: E2E Smoke Tests (Chromium)
  • GitHub Check: opencode-review
🔇 Additional comments (9)
web-ui/src/components/TaskList.tsx (4)

14-14: LGTM!

The tasksApi import correctly references the new API module for the assignment feature.


182-184: LGTM!

The assignment state variables follow proper patterns for managing async operation lifecycle (loading + error states).


240-256: LGTM with a minor observation.

The handler correctly manages loading state, clears previous errors, and handles both API-level failures (!success) and network exceptions. The useCallback dependency array is correct.

One consideration: Axios errors may contain less user-friendly messages (e.g., "Request failed with status code 500"). If improved error messaging is desired, you could extract the server's error detail from error.response?.data?.detail.


306-336: Well-implemented assignment banner.

The banner correctly:

  • Uses Nova design system variables (bg-muted/50, text-foreground, etc.) per coding guidelines
  • Provides clear contextual messaging for in-progress vs. waiting states
  • Disables the button appropriately during assignment or when tasks are running
  • Displays errors prominently when they occur

The grammar handling for singular/plural ("task is" vs "tasks are") is a nice touch for UX polish.

tests/ui/test_assign_pending_tasks.py (5)

17-57: Well-structured test fixtures.

The fixtures are clean, documented, and follow good practices:

  • mock_background_tasks correctly clears ANTHROPIC_API_KEY for deterministic behavior
  • Using spec=BackgroundTasks ensures mock integrity
  • Clear setup for the "happy path" in mock_db

247-304: LGTM!

The tests for execution-in-progress blocking are comprehensive:

  • test_assign_pending_tasks_blocked_when_execution_in_progress correctly verifies that the background task is NOT scheduled when tasks are already running
  • test_assign_pending_tasks_allowed_when_no_execution_in_progress confirms execution proceeds normally otherwise

Both tests have clear assertions covering success, pending_count, message content, and add_task invocation.


307-322: LGTM!

Basic structural validation of the response model. This ensures the model contract is maintained.


325-339: LGTM!

The signature test is a useful contract verification that catches accidental breaking changes to the endpoint interface.


60-61: Good test coverage for the new endpoint.

The test suite covers:

  • Success paths (pending tasks exist, no pending tasks)
  • Error paths (wrong phase, not found, access denied)
  • Edge cases (missing API key, counting logic, concurrent execution blocking)
  • Model structure and function signature validation

This provides solid confidence for the Issue #248 fix.

@github-actions
Copy link
Contributor

Code Review Summary

🔴 Blocking Issue (NOT YET FIXED)

**** - Misleading response when API key missing

The endpoint returns with message "Assignment started..." even when is not configured and no background task is scheduled. This will confuse users who think assignment is happening when nothing will occur.

# Current (lines 482-486):
return TaskAssignmentResponse(
    success=True,  # ❌ Misleading!
    pending_count=pending_count,
    message=f"Assignment started for {pending_count} pending task(s)."
)

Fix required: Move the return statement inside the block and return when API key is missing.


✅ Issues Already Addressed

The following improvements from previous reviews have been implemented:

  1. Concurrent execution prevention (tasks.py:453-464): Added check for tasks that returns a helpful message without triggering duplicate executions
  2. Root cause fix (lead_agent.py:1875): Sets before status change to ensure UI shows assignment immediately
  3. Frontend state management (TaskList.tsx): Proper loading/error states and button disabled when execution in progress

⚠️ Additional Observations

1. Minor inconsistency in test coverage

The test (test_assign_pending_tasks.py:210) expects when API key is missing. Once the blocking issue is fixed, this test assertion should be updated to expect .

2. Frontend error handling could be more specific

In TaskList.tsx:251, the error handler uses generic error messages. Consider extracting server messages from for better user feedback:

const errorMessage = ((error as any)?.response?.data?.message as string) 
    ?? (error instanceof Error ? error.message : 'Failed to assign tasks');

📊 Overall Assessment

Code Quality: Good - follows FastAPI/React patterns, proper authorization checks
Test Coverage: Excellent - 9 unit tests + 2 integration tests covering edge cases
Security: Proper authorization in place
Performance: Appropriate use of background tasks

Status: 🔴 1 blocking issue prevents merge - Fix the API key response logic


🎯 Recommendation

Fix the blocking issue by modifying tasks.py:467-486 to:

if api_key:
    background_tasks.add_task(...)
    logger.info(f"✅ Scheduled task assignment for project {project_id} ({pending_count} pending tasks)")
    return TaskAssignmentResponse(
        success=True,
        pending_count=pending_count,
        message=f"Assignment started for {pending_count} pending task(s)."
    )
else:
    logger.warning(f"⚠️  ANTHROPIC_API_KEY not configured - cannot assign tasks for project {project_id}")
    return TaskAssignmentResponse(
        success=False,
        pending_count=pending_count,
        message="Cannot assign tasks: API key not configured. Please contact your administrator."
    )

After this fix, update test_assign_pending_tasks.py:210 to assert .

@github-actions
Copy link
Contributor

Code Review Complete

Reviewed PR #250 and posted a comprehensive review comment at:
#250 (comment)

🔴 Blocking Issue Found

codeframe/ui/routers/tasks.py:482-486 - Returns success=True even when ANTHROPIC_API_KEY is missing, misleading users into thinking assignment started when nothing happens.

This issue was raised by all previous reviewers (macroscopeapp, coderabbitai, github-actions) but has not been fixed in the current code.

✅ Issues Already Addressed

  1. Concurrent execution prevention - Added in commit 3cbdff5
  2. Root cause fix - Sets assigned_to before status change in lead_agent.py
  3. Frontend state management - Proper loading/error handling in TaskList.tsx

📊 Overall Assessment

Criteria Rating
Code Quality Good - follows FastAPI/React patterns
Test Coverage Excellent - 9 unit + 2 integration tests
Security Proper authorization checks
Performance Appropriate use of background tasks

Status: 🔴 1 blocking issue prevents merge - Fix API key response logic at tasks.py:467-486

New%20session%20-%202026-01-12T01%3A04%3A04.644Z
opencode session  |  github run

@frankbria frankbria linked an issue Jan 12, 2026 that may be closed by this pull request
- Return success=False when API key missing (blocking issue)
- Add ASSIGNED status check to prevent duplicate triggers
- Add debug logging for zero pending tasks case
- Add test for ASSIGNED status blocking
@github-actions
Copy link
Contributor

Code Review Summary

Blocking Issue FIXED

The API key handling issue raised by previous reviewers has been successfully addressed in commit 5c06e22.

Fix Verified (tasks.py:476-500):

  • When ANTHROPIC_API_KEY is missing, the endpoint now correctly returns success=False with a clear error message
  • Background task is only scheduled when API key is present
  • Test test_assign_pending_tasks_without_api_key (line 210) correctly asserts success is False

📊 Overall Assessment

Criteria Rating
Code Quality ✅ Excellent - follows FastAPI/React patterns
Test Coverage ✅ Comprehensive - 9 unit + 2 integration tests
Security ✅ Proper authorization checks
Performance ✅ Appropriate use of background tasks

Status: ✅ Ready to merge - All blocking issues resolved


📝 Optional Improvements (Non-blocking)

1. Frontend Error Handling Enhancement

Location: web-ui/src/components/TaskList.tsx:251

Currently uses generic error messages. Could extract server messages for better user feedback:

const errorMessage = ((error as any)?.response?.data?.message as string) 
    ?? (error instanceof Error ? error.message : 'Failed to assign tasks');

2. Performance Optimization (Minor)

Location: web-ui/src/components/TaskList.tsx:222-233

Two memos iterate projectTasks with identical filter. Could combine:

const pendingUnassignedCount = useMemo(() => {
  return projectTasks.filter(
    (task) => task.status === 'pending' && !task.agent_id
  ).length;
}, [projectTasks]);

const hasPendingUnassigned = pendingUnassignedCount > 0;

Strengths

  1. Root cause fix - Setting assigned_to before status change in lead_agent.py:1875 ensures UI displays assignment immediately
  2. Concurrent execution prevention - Properly checks for ASSIGNED/IN_PROGRESS tasks before scheduling
  3. Comprehensive tests - Edge cases well covered (API key missing, no pending tasks, wrong phase, etc.)
  4. Clean implementation - Follows existing patterns in codebase

Verdict: ✅ LGTM - The PR is well-structured and addresses all requirements. The optional improvements above are nice-to-haves for future iterations.

@github-actions
Copy link
Contributor

Review Complete

I've reviewed PR #250 and posted my feedback as a comment on the PR.

Summary

Status: ✅ Ready to merge

Key Findings

  1. ✅ Blocking Issue FIXED - The API key handling issue has been successfully addressed in commit 5c06e22. The endpoint now correctly returns success=False when ANTHROPIC_API_KEY is missing, with a clear error message.

  2. ✅ Code Quality - Excellent implementation following FastAPI and React patterns. Proper authorization checks, clean state management, and comprehensive test coverage.

  3. ✅ Root Cause Fix - Setting assigned_to before status change in lead_agent.py:1875 correctly addresses the display bug where tasks showed as "Unassigned" during execution.

  4. ✅ Concurrent Execution Prevention - Properly checks for ASSIGNED/IN_PROGRESS tasks before scheduling background execution.

Optional Improvements (Non-blocking)

  1. Frontend Error Handling (TaskList.tsx:251) - Could extract server messages from Axios responses for better user feedback
  2. Performance (TaskList.tsx:222-233) - Two memos could be combined to avoid redundant filtering

Test Coverage

  • ✅ 9 unit tests covering success/error paths
  • ✅ 2 integration tests verifying assignment behavior
  • ✅ Edge cases well covered (API key missing, no pending tasks, wrong phase, etc.)

The PR is well-structured with good test coverage and all blocking issues resolved. The suggested improvements are nice-to-haves for future iterations.

New%20session%20-%202026-01-12T01%3A16%3A16.317Z
opencode session  |  github run

@frankbria frankbria merged commit 5d13d29 into main Jan 12, 2026
13 checks passed
@frankbria frankbria deleted the feature/248-assign-tasks-button branch January 12, 2026 01:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants