diff --git a/__tests__/lib/chart-colors.test.ts b/__tests__/lib/chart-colors.test.ts index b8d0be2..dc316bd 100644 --- a/__tests__/lib/chart-colors.test.ts +++ b/__tests__/lib/chart-colors.test.ts @@ -34,7 +34,7 @@ describe('chart-colors', () => { it('JOB_STATUS_COLORS has all ClaudeJobStatus keys and non-empty values', () => { const keys: (keyof typeof JOB_STATUS_COLORS)[] = [ - 'queued', 'claimed', 'running', 'done', 'failed', 'cancelled', + 'queued', 'claimed', 'running', 'done', 'failed', 'cancelled', 'skipped', ] for (const key of keys) { expect(JOB_STATUS_COLORS[key]).toBeTruthy() diff --git a/__tests__/lib/idea-status.test.ts b/__tests__/lib/idea-status.test.ts index 9bedd32..b72692c 100644 --- a/__tests__/lib/idea-status.test.ts +++ b/__tests__/lib/idea-status.test.ts @@ -41,6 +41,7 @@ describe('canTransition', () => { it('allows re-grill from GRILLED and PLAN_READY-ish states', () => { expect(canTransition('GRILLED', 'GRILLING')).toBe(true) expect(canTransition('PLAN_FAILED', 'PLANNING')).toBe(true) + expect(canTransition('PLAN_READY', 'GRILLING')).toBe(true) }) it('allows fail-side transitions', () => { @@ -60,8 +61,8 @@ describe('canTransition', () => { }) it('canTransition to GRILLING from all statuses that allow re-grill', () => { - // DRAFT, GRILLED, GRILL_FAILED, PLANNED are in GRILL_TRIGGERABLE_FROM and support the transition. - const regrill = ['DRAFT', 'GRILLED', 'GRILL_FAILED', 'PLANNED'] as const + // GRILL_TRIGGERABLE_FROM in actions/ideas.ts — alle statussen die re-grill ondersteunen. + const regrill = ['DRAFT', 'GRILLED', 'GRILL_FAILED', 'PLAN_READY', 'PLANNED'] as const for (const status of regrill) { expect(canTransition(status, 'GRILLING')).toBe(true) } diff --git a/__tests__/lib/insights/agent-throughput.test.ts b/__tests__/lib/insights/agent-throughput.test.ts index 3465dd4..31bf46d 100644 --- a/__tests__/lib/insights/agent-throughput.test.ts +++ b/__tests__/lib/insights/agent-throughput.test.ts @@ -48,7 +48,7 @@ describe('getJobsPerDay', () => { // All days should have zero counts except the three we seeded const nonZero = result.perDay.filter( - d => d.done + d.failed + d.queued + d.claimed + d.running + d.cancelled > 0, + d => d.done + d.failed + d.queued + d.claimed + d.running + d.cancelled + d.skipped > 0, ) expect(nonZero).toHaveLength(3) diff --git a/__tests__/lib/job-status.test.ts b/__tests__/lib/job-status.test.ts index db8d1ab..dee082e 100644 --- a/__tests__/lib/job-status.test.ts +++ b/__tests__/lib/job-status.test.ts @@ -27,13 +27,14 @@ describe('job-status mappers', () => { expect(jobStatusFromApi('QUEUED')).toBe('QUEUED') }) - it('maps all 6 DB statuses to API', () => { + it('maps all 7 DB statuses to API', () => { expect(jobStatusToApi('QUEUED')).toBe('queued') expect(jobStatusToApi('CLAIMED')).toBe('claimed') expect(jobStatusToApi('RUNNING')).toBe('running') expect(jobStatusToApi('DONE')).toBe('done') expect(jobStatusToApi('FAILED')).toBe('failed') expect(jobStatusToApi('CANCELLED')).toBe('cancelled') + expect(jobStatusToApi('SKIPPED')).toBe('skipped') }) it('ACTIVE_JOB_STATUSES contains exactly QUEUED, CLAIMED, RUNNING', () => { diff --git a/app/(app)/insights/components/agent-throughput.tsx b/app/(app)/insights/components/agent-throughput.tsx index 820e64f..a43dd96 100644 --- a/app/(app)/insights/components/agent-throughput.tsx +++ b/app/(app)/insights/components/agent-throughput.tsx @@ -33,7 +33,7 @@ function formatDuration(seconds: number | null): string { return m > 0 ? `${m}m ${s}s` : `${s}s` } -const STACKED_STATUSES = ['queued', 'claimed', 'running', 'done', 'failed', 'cancelled'] as const +const STACKED_STATUSES = ['queued', 'claimed', 'running', 'done', 'failed', 'cancelled', 'skipped'] as const export function AgentThroughputCard({ data, productList, currentProductId }: Props) { const router = useRouter() @@ -44,7 +44,7 @@ export function AgentThroughputCard({ data, productList, currentProductId }: Pro const { perDay, kpi } = data const isEmpty = perDay.every( - d => d.done + d.failed + d.queued + d.claimed + d.running + d.cancelled === 0, + d => d.done + d.failed + d.queued + d.claimed + d.running + d.cancelled + d.skipped === 0, ) function handleProductChange(value: string | null) { diff --git a/lib/chart-colors.ts b/lib/chart-colors.ts index 561d4dc..e7b2d9f 100644 --- a/lib/chart-colors.ts +++ b/lib/chart-colors.ts @@ -28,6 +28,7 @@ export const JOB_STATUS_COLORS = { done: 'var(--status-done)', failed: 'var(--priority-critical)', cancelled: 'var(--muted-foreground)', + skipped: 'var(--muted-foreground)', } as const export const SERIES_COLORS = [ diff --git a/lib/idea-status.ts b/lib/idea-status.ts index 1cc94b2..e513245 100644 --- a/lib/idea-status.ts +++ b/lib/idea-status.ts @@ -53,7 +53,7 @@ const ALLOWED_TRANSITIONS: Record> = { GRILLED: ['GRILLING', 'PLANNING'], PLANNING: ['PLAN_READY', 'PLAN_FAILED'], PLAN_FAILED: ['PLANNING', 'GRILLED'], - PLAN_READY: ['PLANNING', 'PLANNED'], + PLAN_READY: ['PLANNING', 'PLANNED', 'GRILLING'], // GRILLING via startGrillJobAction (re-grill) PLANNED: ['PLAN_READY', 'GRILLING'], // PLAN_READY via relinkIdeaPlanAction; GRILLING via startGrillJobAction } diff --git a/lib/insights/agent-throughput.ts b/lib/insights/agent-throughput.ts index b5017d2..3e172aa 100644 --- a/lib/insights/agent-throughput.ts +++ b/lib/insights/agent-throughput.ts @@ -8,6 +8,7 @@ export interface DayCount { done: number failed: number cancelled: number + skipped: number } export interface ThroughputKpi { @@ -21,6 +22,8 @@ export interface JobsPerDayResult { kpi: ThroughputKpi } +const STATUSES = ['queued', 'claimed', 'running', 'done', 'failed', 'cancelled', 'skipped'] as const + type RawDayRow = { day: Date; status: string; count: bigint } type RawKpiRow = { today_count: bigint; done_7d: bigint; terminal_7d: bigint; avg_seconds: number | null } @@ -98,6 +101,7 @@ export async function getJobsPerDay( done: statusMap.get('done') ?? 0, failed: statusMap.get('failed') ?? 0, cancelled: statusMap.get('cancelled') ?? 0, + skipped: statusMap.get('skipped') ?? 0, }) }