diff --git a/.jules/bolt.md b/.jules/bolt.md index 57daf471..12a0bb7d 100644 --- a/.jules/bolt.md +++ b/.jules/bolt.md @@ -3,3 +3,9 @@ **Learning:** `Date.parse(value)` returns the timestamp primitive directly, while `new Date(value).getTime()` also constructs a `Date` object. Both use the same ECMAScript string-parsing semantics for these call sites. **Action:** In frequently executed paths that only need a timestamp primitive, prefer `Date.parse(value)`. Treat the allocation reduction as a bounded micro-optimization unless a committed benchmark establishes a larger runtime effect. + +## 2026-09-06 - Schwartzian transform for expensive sort comparators + +**Learning:** When sorting large arrays based on an expensive data transformation like `Date.parse()` on ISO strings, placing the transformation directly inside the `Array.prototype.sort()` comparator causes it to execute O(N log N) times. A Schwartzian transform (map-sort-map) pre-computes the values in O(N) time. + +**Action:** Wrap items in an object `{ original: item, parsedValue: expensiveOperation(item) }` prior to sorting when the comparator relies on computationally non-trivial operations. diff --git a/packages/web/src/components/dashboard/session-timeline-chart.tsx b/packages/web/src/components/dashboard/session-timeline-chart.tsx index 222d0b22..6e66ee21 100644 --- a/packages/web/src/components/dashboard/session-timeline-chart.tsx +++ b/packages/web/src/components/dashboard/session-timeline-chart.tsx @@ -67,9 +67,10 @@ 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((item) => ({ original: item, parsedValue: Date.parse(item.timestamp) })) + .sort((a, b) => a.parsedValue - b.parsedValue) + const sortedTools = [...toolCalls].sort( (a, b) => a.parsedTimestamp - b.parsedTimestamp ) @@ -77,9 +78,7 @@ function buildChartData( let toolIndex = 0 const cumulativeToolCounts = new Map() - return sortedUsage.map((usage) => { - const currentTimestamp = Date.parse(usage.timestamp) - + return sortedUsage.map(({ original: usage, parsedValue: currentTimestamp }) => { while ( toolIndex < sortedTools.length && sortedTools[toolIndex]!.parsedTimestamp <= currentTimestamp