Files
WHOOSH/docs/TASK-UI-ISSUES-ANALYSIS.md
Claude Code 3373f7b462
Some checks failed
WHOOSH CI / speclint (push) Has been cancelled
WHOOSH CI / contracts (push) Has been cancelled
Add chorus-entrypoint label to standardized label set
**Problem**: The standardized label set was missing the `chorus-entrypoint`
label, which is present in CHORUS repository and required for triggering
council formation for project kickoffs.

**Changes**:
- Added `chorus-entrypoint` label (#ff6b6b) to `EnsureRequiredLabels()`
  in `internal/gitea/client.go`
- Now creates 9 standard labels (was 8):
  1. bug
  2. bzzz-task
  3. chorus-entrypoint (NEW)
  4. duplicate
  5. enhancement
  6. help wanted
  7. invalid
  8. question
  9. wontfix

**Testing**:
- Rebuilt and deployed WHOOSH with updated label configuration
- Synced labels to all 5 monitored repositories (whoosh-ui,
  SequentialThinkingForCHORUS, TEST, WHOOSH, CHORUS)
- Verified all repositories now have complete 9-label set

**Impact**: All CHORUS ecosystem repositories now have consistent labeling
matching the CHORUS repository standard, enabling proper council formation
triggers.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-12 22:06:10 +11:00

14 KiB

Task UI Issues Analysis

Problem Statement

Tasks displayed in the WHOOSH UI show "undefined" fields and placeholder text like "Help Promises: (Not implemented)" and "Retry Budgets: (Not implemented)".

Root Cause Analysis

1. UI Displaying Non-Existent Fields

Location: ui/script.js lines ~290-310 (loadTaskDetail function)

Current Code:

async function loadTaskDetail(taskId) {
    const task = await apiFetch(`/v1/tasks/${taskId}`);
    taskContent.innerHTML = `
        <h2>${task.title}</h2>
        <div class="card">
            <h3>Task Details</h3>
            <div class="grid">
                <div>
                    <p><strong>Status:</strong> ${task.status}</p>
                    <p><strong>Priority:</strong> ${task.priority}</p>
                </div>
                <div>
                    <p><strong>Help Promises:</strong> (Not implemented)</p>
                    <p><strong>Retry Budgets:</strong> (Not implemented)</p>
                </div>
            </div>
            <hr>
            <p><strong>Description:</strong></p>
            <p>${task.description}</p>
        </div>
    `;
}

Issue: "Help Promises" and "Retry Budgets" are hard-coded placeholder text, not actual fields from the Task model.

2. Missing Task Fields in UI

Task Model (internal/tasks/models.go):

type Task struct {
    ID               uuid.UUID
    ExternalID       string
    ExternalURL      string
    SourceType       SourceType
    Title            string
    Description      string
    Status           TaskStatus
    Priority         TaskPriority
    AssignedTeamID   *uuid.UUID
    AssignedAgentID  *uuid.UUID
    Repository       string
    ProjectID        string
    Labels           []string
    TechStack        []string
    Requirements     []string
    EstimatedHours   int
    ComplexityScore  float64
    ClaimedAt        *time.Time
    StartedAt        *time.Time
    CompletedAt      *time.Time
    CreatedAt        time.Time
    UpdatedAt        time.Time
}

Fields NOT displayed in UI:

  • Repository
  • ProjectID
  • Labels
  • TechStack
  • Requirements
  • EstimatedHours
  • ComplexityScore
  • ExternalURL (link to GITEA issue)
  • AssignedTeamID/AssignedAgentID
  • Timestamps (claimed_at, started_at, completed_at)

3. API Endpoint Issues

Expected Endpoint: /api/v1/tasks Actual Status: Returns 404

Possible Causes:

  1. Route Registration: The route exists in code but may not be in the deployed image
  2. Image Version: Running image anthonyrawlins/whoosh:council-team-fix may pre-date the /v1/tasks endpoint
  3. Alternative Access Pattern: Tasks may need to be accessed via /api/v1/projects/{projectID}/tasks

Evidence from code:

  • internal/server/server.go shows both endpoints exist:
    • /api/v1/tasks (standalone tasks endpoint)
    • /api/v1/projects/{projectID}/tasks (project-scoped tasks)

4. Undefined Field Values

When the UI attempts to display task fields that don't exist in the API response, JavaScript will show undefined.

Example Scenario:

// If API returns task without 'estimated_hours'
<p><strong>Estimated Hours:</strong> ${task.estimated_hours}</p>
// Renders as: "Estimated Hours: undefined"

Impact Assessment

Current State

  1. Task model in database has all necessary fields
  2. Task service can query and return complete task data
  3. UI only displays: title, status, priority, description
  4. UI shows placeholder text for non-existent fields
  5. Many useful task fields are not displayed
  6. /v1/tasks API endpoint returns 404 (needs verification)

User Impact

  • Low Information Density: Users can't see repository, labels, tech stack, requirements
  • No Assignment Visibility: Can't see which team/agent claimed the task
  • No Time Tracking: Can't see when task was claimed/started/completed
  • Confusing Placeholders: "(Not implemented)" text suggests incomplete features
  • No External Links: Can't click through to GITEA issue

Phase 1: Fix UI Display (HIGH PRIORITY)

1.1 Remove Placeholder Text

// REMOVE these lines from loadTaskDetail():
<p><strong>Help Promises:</strong> (Not implemented)</p>
<p><strong>Retry Budgets:</strong> (Not implemented)</p>

1.2 Add Missing Fields

async function loadTaskDetail(taskId) {
    const task = await apiFetch(`/v1/tasks/${taskId}`);
    taskContent.innerHTML = `
        <h2>${task.title}</h2>

        <div class="card">
            <h3>Task Details</h3>

            <!-- Basic Info -->
            <div class="grid">
                <div>
                    <p><strong>Status:</strong> <span class="badge status-${task.status}">${task.status}</span></p>
                    <p><strong>Priority:</strong> <span class="badge priority-${task.priority}">${task.priority}</span></p>
                    <p><strong>Source:</strong> ${task.source_type}</p>
                </div>
                <div>
                    <p><strong>Repository:</strong> ${task.repository || 'N/A'}</p>
                    <p><strong>Project ID:</strong> ${task.project_id || 'N/A'}</p>
                    ${task.external_url ? `<p><strong>Issue:</strong> <a href="${task.external_url}" target="_blank">View on GITEA</a></p>` : ''}
                </div>
            </div>

            <!-- Estimation & Complexity -->
            ${task.estimated_hours || task.complexity_score ? `
            <hr>
            <div class="grid">
                ${task.estimated_hours ? `<p><strong>Estimated Hours:</strong> ${task.estimated_hours}</p>` : ''}
                ${task.complexity_score ? `<p><strong>Complexity Score:</strong> ${task.complexity_score.toFixed(2)}</p>` : ''}
            </div>
            ` : ''}

            <!-- Labels & Tech Stack -->
            ${task.labels?.length || task.tech_stack?.length ? `
            <hr>
            <div class="grid">
                ${task.labels?.length ? `
                <div>
                    <p><strong>Labels:</strong></p>
                    <div class="tags">
                        ${task.labels.map(label => `<span class="tag">${label}</span>`).join('')}
                    </div>
                </div>
                ` : ''}
                ${task.tech_stack?.length ? `
                <div>
                    <p><strong>Tech Stack:</strong></p>
                    <div class="tags">
                        ${task.tech_stack.map(tech => `<span class="tag tech">${tech}</span>`).join('')}
                    </div>
                </div>
                ` : ''}
            </div>
            ` : ''}

            <!-- Requirements -->
            ${task.requirements?.length ? `
            <hr>
            <p><strong>Requirements:</strong></p>
            <ul>
                ${task.requirements.map(req => `<li>${req}</li>`).join('')}
            </ul>
            ` : ''}

            <!-- Description -->
            <hr>
            <p><strong>Description:</strong></p>
            <div class="description">
                ${task.description || '<em>No description provided</em>'}
            </div>

            <!-- Assignment Info -->
            ${task.assigned_team_id || task.assigned_agent_id ? `
            <hr>
            <p><strong>Assignment:</strong></p>
            <div class="grid">
                ${task.assigned_team_id ? `<p>Team: ${task.assigned_team_id}</p>` : ''}
                ${task.assigned_agent_id ? `<p>Agent: ${task.assigned_agent_id}</p>` : ''}
            </div>
            ` : ''}

            <!-- Timestamps -->
            <hr>
            <div class="grid timestamps">
                <p><strong>Created:</strong> ${new Date(task.created_at).toLocaleString()}</p>
                ${task.claimed_at ? `<p><strong>Claimed:</strong> ${new Date(task.claimed_at).toLocaleString()}</p>` : ''}
                ${task.started_at ? `<p><strong>Started:</strong> ${new Date(task.started_at).toLocaleString()}</p>` : ''}
                ${task.completed_at ? `<p><strong>Completed:</strong> ${new Date(task.completed_at).toLocaleString()}</p>` : ''}
            </div>
        </div>
    `;
}

1.3 Add Corresponding CSS

Add to ui/styles.css:

.badge {
    padding: 0.25rem 0.5rem;
    border-radius: 4px;
    font-size: 0.875rem;
    font-weight: 500;
}

.status-open { background-color: #3b82f6; color: white; }
.status-claimed { background-color: #8b5cf6; color: white; }
.status-in_progress { background-color: #f59e0b; color: white; }
.status-completed { background-color: #10b981; color: white; }
.status-closed { background-color: #6b7280; color: white; }
.status-blocked { background-color: #ef4444; color: white; }

.priority-critical { background-color: #dc2626; color: white; }
.priority-high { background-color: #f59e0b; color: white; }
.priority-medium { background-color: #3b82f6; color: white; }
.priority-low { background-color: #6b7280; color: white; }

.tags {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin-top: 0.5rem;
}

.tag {
    padding: 0.25rem 0.75rem;
    background-color: #e5e7eb;
    border-radius: 12px;
    font-size: 0.875rem;
}

.tag.tech {
    background-color: #dbeafe;
    color: #1e40af;
}

.description {
    white-space: pre-wrap;
    line-height: 1.6;
    padding: 1rem;
    background-color: #f9fafb;
    border-radius: 4px;
}

.timestamps {
    font-size: 0.875rem;
    color: #6b7280;
}

Phase 2: Verify API Endpoint (MEDIUM PRIORITY)

2.1 Test Current Endpoint

# Check if /v1/tasks works
curl -v http://whoosh.chorus.services/api/v1/tasks

# If 404, try project-scoped endpoint
curl http://whoosh.chorus.services/api/v1/projects | jq '.projects[0].id'
# Then
curl http://whoosh.chorus.services/api/v1/projects/{PROJECT_ID}/tasks

2.2 Update UI Route If Needed

If /v1/tasks doesn't exist in deployed version, update UI to use project-scoped endpoint:

// Option A: Load from specific project
const task = await apiFetch(`/v1/projects/${projectId}/tasks/${taskNumber}`);

// Option B: Rebuild and deploy WHOOSH with /v1/tasks endpoint

Phase 3: Task List Enhancement (LOW PRIORITY)

3.1 Improve Task List Display

async function loadTasks() {
    const tasksContent = document.getElementById('tasks-content');
    try {
        const data = await apiFetch('/v1/tasks');
        tasksContent.innerHTML = `
            <div class="task-list">
                ${data.tasks.map(task => `
                    <div class="task-card">
                        <h3><a href="#tasks/${task.id}">${task.title}</a></h3>
                        <div class="task-meta">
                            <span class="badge status-${task.status}">${task.status}</span>
                            <span class="badge priority-${task.priority}">${task.priority}</span>
                            ${task.repository ? `<span class="repo-badge">${task.repository}</span>` : ''}
                        </div>
                        ${task.tech_stack?.length ? `
                        <div class="tags">
                            ${task.tech_stack.slice(0, 3).map(tech => `
                                <span class="tag tech">${tech}</span>
                            `).join('')}
                            ${task.tech_stack.length > 3 ? `<span class="tag">+${task.tech_stack.length - 3} more</span>` : ''}
                        </div>
                        ` : ''}
                        ${task.description ? `
                        <p class="task-description">${task.description.substring(0, 150)}...</p>
                        ` : ''}
                    </div>
                `).join('')}
            </div>
        `;
    } catch (error) {
        tasksContent.innerHTML = `<p class="error">Error loading tasks: ${error.message}</p>`;
    }
}

Implementation Plan

Step 1: Quick Win - Remove Placeholders (5 minutes)

  1. Open ui/script.js
  2. Find loadTaskDetail function
  3. Remove lines with "Help Promises" and "Retry Budgets"
  4. Commit and deploy

Step 2: Add Essential Fields (30 minutes)

  1. Add repository, project_id, external_url to task detail view
  2. Add labels and tech_stack display
  3. Add timestamps display
  4. Test locally

Step 3: Add Styling (15 minutes)

  1. Add badge styles for status/priority
  2. Add tag styles for labels/tech stack
  3. Add description formatting
  4. Test visual appearance

Step 4: Deploy (10 minutes)

  1. Build new WHOOSH image with UI changes
  2. Tag as anthonyrawlins/whoosh:task-ui-fix
  3. Deploy to swarm
  4. Verify in browser

Step 5: API Verification (Optional)

  1. Test if /v1/tasks endpoint works after deploy
  2. If not, rebuild WHOOSH binary with latest code
  3. Or update UI to use project-scoped endpoints

Testing Checklist

  • Task detail page loads without "undefined" values
  • No placeholder "(Not implemented)" text visible
  • Repository name displays correctly
  • Labels render as styled tags
  • Tech stack renders as styled tags
  • External URL link works and opens GITEA issue
  • Timestamps format correctly
  • Status badge has correct color
  • Priority badge has correct color
  • Description text wraps properly
  • Null/empty fields don't break layout

Future Enhancements

  1. Interactive Task Management

    • Claim task button
    • Update status dropdown
    • Add comment/note functionality
  2. Task Filtering

    • Filter by status, priority, repository
    • Search by title/description
    • Filter by tech stack
  3. Task Analytics

    • Time to completion metrics
    • Complexity vs actual hours
    • Agent performance by task type
  4. Visualization

    • Kanban board view
    • Timeline view
    • Dependency graph

References

  • Task Model: internal/tasks/models.go
  • Task Service: internal/tasks/service.go
  • UI JavaScript: ui/script.js
  • UI Styles: ui/styles.css
  • API Routes: internal/server/server.go