US-1502/1503/1504: Propagate review → blocked across entire codebase

Frontend (US-1502 & US-1503):
- KanbanBoard.tsx: Column id/title changed to 'blocked'/'Blocked'
- KanbanColumn.tsx: Color changed from amber-500 to red-500
- Dashboard.tsx: Metric card label/icon/color updated
- TaskMetadataSection.tsx: Status label updated
- useKeyboard.tsx: Keyboard shortcuts updated
- useTasks.ts: tasksByStatus keys updated

Backend (US-1504):
- automation.ts: Task status on completion changed
- notifications.ts: Status check updated
- summary.ts: Status filtering updated
- clawdbot-agent-service.ts: Success now sets 'done' instead of 'review'
- metrics-service.ts: Status keys updated
This commit is contained in:
Brad Groux 2026-01-28 06:51:28 -06:00
parent 3c2eb55ca8
commit c1ee77eb33
13 changed files with 54 additions and 19 deletions

View file

@ -604,3 +604,5 @@
{"type":"task.status_changed","taskId":"task_20260128_ksQUvs","project":"veritas-kanban","status":"in-progress","previousStatus":"todo","id":"evt_WyBRK_mNhgAl","timestamp":"2026-01-28T12:34:14.344Z"}
{"type":"task.status_changed","taskId":"task_20260128_ksQUvs","project":"veritas-kanban","status":"done","previousStatus":"in-progress","id":"evt_W2qXAeCbQMx-","timestamp":"2026-01-28T12:45:58.771Z"}
{"type":"task.status_changed","taskId":"task_20260128_-WSaw3","project":"veritas-kanban","status":"in-progress","previousStatus":"todo","id":"evt_5rubDBi7a4sp","timestamp":"2026-01-28T12:46:18.174Z"}
{"type":"task.status_changed","taskId":"task_20260128_-WSaw3","project":"veritas-kanban","status":"done","previousStatus":"in-progress","id":"evt_FnNCrt7n93W-","timestamp":"2026-01-28T12:48:06.446Z"}
{"type":"task.status_changed","taskId":"task_20260128_iFFyez","project":"veritas-kanban","status":"in-progress","previousStatus":"todo","id":"evt_V84NFTY9QFuT","timestamp":"2026-01-28T12:48:25.548Z"}

View file

@ -1,4 +1,37 @@
[
{
"id": "activity_1769604505548_u0nvgi0nq",
"type": "status_changed",
"taskId": "task_20260128_iFFyez",
"taskTitle": "US-1502: Update Kanban column display — Blocked title + red color",
"details": {
"from": "todo",
"status": "in-progress"
},
"timestamp": "2026-01-28T12:48:25.548Z"
},
{
"id": "activity_1769604486483_yln4lo1t6",
"type": "comment_added",
"taskId": "task_20260128_-WSaw3",
"taskTitle": "US-1501: Rename TaskStatus review → blocked in shared types",
"details": {
"author": "Veritas",
"preview": "Updated TaskStatus from review → blocked in types ..."
},
"timestamp": "2026-01-28T12:48:06.483Z"
},
{
"id": "activity_1769604486446_s45ozs78g",
"type": "status_changed",
"taskId": "task_20260128_-WSaw3",
"taskTitle": "US-1501: Rename TaskStatus review → blocked in shared types",
"details": {
"from": "in-progress",
"status": "done"
},
"timestamp": "2026-01-28T12:48:06.446Z"
},
{
"id": "activity_1769604473427_cksmodaid",
"type": "task_updated",

View file

@ -81,7 +81,7 @@ router.post('/:taskId/complete', async (req, res) => {
// Update task
const updated = await taskService.updateTask(task.id, {
status: isSuccess ? 'done' : 'review',
status: isSuccess ? 'done' : 'blocked',
attempt: {
...task.attempt,
status: isSuccess ? 'complete' : 'failed',
@ -119,7 +119,7 @@ router.get('/pending', async (_req, res) => {
const pending = tasks.filter(task => {
if (task.type !== 'automation') return false;
if (task.status === 'todo') return true;
if (task.status === 'review' && task.attempt?.agent === 'veritas' && task.attempt?.status === 'failed') {
if (task.status === 'blocked' && task.attempt?.agent === 'veritas' && task.attempt?.status === 'failed') {
return true; // Failed, might need retry
}
return false;

View file

@ -194,7 +194,7 @@ router.post('/check', asyncHandler(async (_req, res) => {
// Check for tasks in review (needs review notification)
const inReview = tasks.filter(t =>
t.status === 'review' &&
t.status === 'blocked' &&
t.attempt?.status === 'complete' &&
t.attempt?.agent !== 'veritas'
);

View file

@ -12,7 +12,7 @@ router.get('/', async (_req, res) => {
const byStatus = {
todo: tasks.filter(t => t.status === 'todo').length,
'in-progress': tasks.filter(t => t.status === 'in-progress').length,
review: tasks.filter(t => t.status === 'review').length,
blocked: tasks.filter(t => t.status === 'blocked').length,
done: tasks.filter(t => t.status === 'done').length,
};
@ -113,7 +113,7 @@ router.get('/memory', async (req, res) => {
// Active high-priority
const highPriority = tasks.filter(t =>
t.priority === 'high' &&
(t.status === 'in-progress' || t.status === 'review')
(t.status === 'in-progress' || t.status === 'blocked')
);
// Build markdown

View file

@ -195,7 +195,7 @@ export class ClawdbotAgentService {
// Update task
await this.taskService.updateTask(taskId, {
status: result.success ? 'review' : 'in-progress',
status: result.success ? 'done' : 'in-progress',
attempt: {
id: attemptId,
agent: pending.agent,

View file

@ -99,7 +99,7 @@ export class MetricsService {
const byStatus: Record<TaskStatus, number> = {
'todo': 0,
'in-progress': 0,
'review': 0,
'blocked': 0,
'done': 0,
};

View file

@ -34,7 +34,7 @@ import FeatureErrorBoundary from '@/components/shared/FeatureErrorBoundary';
const COLUMNS: { id: TaskStatus; title: string }[] = [
{ id: 'todo', title: 'To Do' },
{ id: 'in-progress', title: 'In Progress' },
{ id: 'review', title: 'Review' },
{ id: 'blocked', title: 'Blocked' },
{ id: 'done', title: 'Done' },
];

View file

@ -17,7 +17,7 @@ interface KanbanColumnProps {
const columnColors: Record<TaskStatus, string> = {
'todo': 'border-t-slate-500',
'in-progress': 'border-t-blue-500',
'review': 'border-t-amber-500',
'blocked': 'border-t-red-500',
'done': 'border-t-green-500',
};

View file

@ -20,7 +20,7 @@ import {
Archive,
ListTodo,
Play,
Eye,
Ban,
RefreshCw
} from 'lucide-react';
import { cn } from '@/lib/utils';
@ -196,10 +196,10 @@ export function Dashboard() {
color="blue"
/>
<MetricCard
label="Review"
value={metrics.tasks.byStatus['review'] || 0}
icon={<Eye className="h-4 w-4" />}
color="yellow"
label="Blocked"
value={metrics.tasks.byStatus['blocked'] || 0}
icon={<Ban className="h-4 w-4" />}
color="red"
/>
<MetricCard
label="Done"

View file

@ -23,7 +23,7 @@ interface TaskMetadataSectionProps {
const statusLabels: Record<TaskStatus, string> = {
'todo': 'To Do',
'in-progress': 'In Progress',
'review': 'Review',
'blocked': 'Blocked',
'done': 'Done',
};

View file

@ -28,7 +28,7 @@ const KeyboardContext = createContext<KeyboardContextValue | null>(null);
const STATUS_MAP: Record<string, TaskStatus> = {
'1': 'todo',
'2': 'in-progress',
'3': 'review',
'3': 'blocked',
'4': 'done',
};
@ -68,7 +68,7 @@ export function KeyboardProvider({ children }: { children: ReactNode }) {
// Get flat list of tasks sorted by column then position
const getTaskList = useCallback(() => {
const statusOrder: TaskStatus[] = ['todo', 'in-progress', 'review', 'done'];
const statusOrder: TaskStatus[] = ['todo', 'in-progress', 'blocked', 'done'];
return [...tasks].sort((a, b) => {
const aIndex = statusOrder.indexOf(a.status);
const bIndex = statusOrder.indexOf(b.status);

View file

@ -204,7 +204,7 @@ export function useTasksByStatus(tasks: Task[] | undefined) {
return {
todo: [],
'in-progress': [],
review: [],
blocked: [],
done: [],
};
}
@ -212,7 +212,7 @@ export function useTasksByStatus(tasks: Task[] | undefined) {
return {
todo: sortByPosition(tasks.filter(t => t.status === 'todo')),
'in-progress': sortByPosition(tasks.filter(t => t.status === 'in-progress')),
review: sortByPosition(tasks.filter(t => t.status === 'review')),
blocked: sortByPosition(tasks.filter(t => t.status === 'blocked')),
done: sortByPosition(tasks.filter(t => t.status === 'done')),
};
}