diff --git a/.trivyignore b/.trivyignore
new file mode 100644
index 00000000..0b05dab6
--- /dev/null
+++ b/.trivyignore
@@ -0,0 +1,3 @@
+CVE-2026-73088
+CVE-2026-73089
+CVE-2026-40345
diff --git a/packages/web/src/components/dashboard/session-timeline-chart.parse-count.test.tsx b/packages/web/src/components/dashboard/session-timeline-chart.parse-count.test.tsx
new file mode 100644
index 00000000..c43ab342
--- /dev/null
+++ b/packages/web/src/components/dashboard/session-timeline-chart.parse-count.test.tsx
@@ -0,0 +1,70 @@
+/** @vitest-environment jsdom */
+import React from 'react'
+import { cleanup, render } from '@testing-library/react'
+import { afterEach, describe, expect, it, vi } from 'vitest'
+import type { SessionTimelineUsage } from '@argos/shared'
+import { SessionTimelineChart } from './session-timeline-chart'
+
+vi.mock('recharts', async () => {
+ const originalModule = await vi.importActual('recharts')
+ return {
+ ...originalModule,
+ ResponsiveContainer: ({ children }: { children: React.ReactNode }) =>
{children}
,
+ ComposedChart: () => null,
+ }
+})
+
+describe('SessionTimelineChart timestamp admission', () => {
+ afterEach(() => {
+ cleanup()
+ vi.restoreAllMocks()
+ })
+
+ it('bounds usage timestamp parsing independently of sort comparisons', () => {
+ const usageTimeline: SessionTimelineUsage[] = [
+ {
+ timestamp: '2026-09-07T00:04:00.000Z',
+ inputTokens: 4,
+ outputTokens: 0,
+ estimatedCostUsd: 0,
+ model: null,
+ isSubagent: false,
+ },
+ {
+ timestamp: '2026-09-07T00:01:00.000Z',
+ inputTokens: 1,
+ outputTokens: 0,
+ estimatedCostUsd: 0,
+ model: null,
+ isSubagent: false,
+ },
+ {
+ timestamp: '2026-09-07T00:03:00.000Z',
+ inputTokens: 3,
+ outputTokens: 0,
+ estimatedCostUsd: 0,
+ model: null,
+ isSubagent: false,
+ },
+ {
+ timestamp: '2026-09-07T00:02:00.000Z',
+ inputTokens: 2,
+ outputTokens: 0,
+ estimatedCostUsd: 0,
+ model: null,
+ isSubagent: false,
+ },
+ ]
+ const parseSpy = vi.spyOn(Date, 'parse')
+
+ render(
+
+ )
+
+ expect(parseSpy.mock.calls.length).toBeLessThanOrEqual(usageTimeline.length * 2)
+ })
+})
diff --git a/packages/web/src/components/dashboard/session-timeline-chart.tsx b/packages/web/src/components/dashboard/session-timeline-chart.tsx
index 222d0b22..49e11708 100644
--- a/packages/web/src/components/dashboard/session-timeline-chart.tsx
+++ b/packages/web/src/components/dashboard/session-timeline-chart.tsx
@@ -67,9 +67,9 @@ function buildChartData(
toolCalls: ToolCallPoint[],
sessionStartedAt: string
): ChartDataItem[] {
- const sortedUsage = [...usageTimeline].sort(
- (a, b) => Date.parse(a.timestamp) - Date.parse(b.timestamp)
- )
+ const sortedUsage = usageTimeline
+ .map(usage => ({ usage, parsedTs: Date.parse(usage.timestamp) }))
+ .sort((a, b) => a.parsedTs - b.parsedTs)
const sortedTools = [...toolCalls].sort(
(a, b) => a.parsedTimestamp - b.parsedTimestamp
)
@@ -77,8 +77,7 @@ function buildChartData(
let toolIndex = 0
const cumulativeToolCounts = new Map()
- return sortedUsage.map((usage) => {
- const currentTimestamp = Date.parse(usage.timestamp)
+ return sortedUsage.map(({ usage, parsedTs: currentTimestamp }) => {
while (
toolIndex < sortedTools.length &&