From a52bfd4a426b91ed03b08319c012be034795358e Mon Sep 17 00:00:00 2001 From: Madhura68 Date: Thu, 7 May 2026 17:01:49 +0200 Subject: [PATCH] feat(ST-1275): render SKIPPED job status in chart-colors and insights MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closing the gap left when ClaudeJobStatus.SKIPPED was added to the schema: the badge map and case-mapper already covered it, but the chart palette, the per-day insights aggregator and the stacked-bar chart did not. SKIPPED jobs (e.g. cmovkur8 manually flipped during the no-op-exit hotfix) now render with a muted style consistent with cancelled. - lib/chart-colors.ts: JOB_STATUS_COLORS gains a 'skipped' entry (var(--muted-foreground), same intensity as cancelled — neither rood/orange) - lib/insights/agent-throughput.ts: DayCount + STATUSES + perDay zero-fill now include 'skipped'; the SQL terminal_7d filter already counted SKIPPED - app/(app)/insights/components/agent-throughput.tsx: STACKED_STATUSES and the empty-state guard include 'skipped' - __tests__: chart-colors keys list, job-status round-trip ('all 7 statuses') and the insights non-zero filter all account for SKIPPED Co-Authored-By: Claude Opus 4.7 (1M context) --- __tests__/lib/chart-colors.test.ts | 2 +- __tests__/lib/insights/agent-throughput.test.ts | 2 +- __tests__/lib/job-status.test.ts | 3 ++- app/(app)/insights/components/agent-throughput.tsx | 4 ++-- lib/chart-colors.ts | 1 + lib/insights/agent-throughput.ts | 4 +++- 6 files changed, 10 insertions(+), 6 deletions(-) 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/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/insights/agent-throughput.ts b/lib/insights/agent-throughput.ts index 2a44340..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,7 +22,7 @@ export interface JobsPerDayResult { kpi: ThroughputKpi } -const STATUSES = ['queued', 'claimed', 'running', 'done', 'failed', 'cancelled'] as const +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 } @@ -100,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, }) }