Skip to content

Fastesterer timeline#3576

Open
GiantRobots wants to merge 32 commits into
mainfrom
FastestererTimeline
Open

Fastesterer timeline#3576
GiantRobots wants to merge 32 commits into
mainfrom
FastestererTimeline

Conversation

@GiantRobots

Copy link
Copy Markdown
Collaborator

Description & motivation 💭

Screenshots (if applicable) 📸

Design Considerations 🎨

Testing 🧪

How was this tested 👻

  • Manual testing
  • E2E tests added
  • Unit tests added

Steps for others to test: 🚶🏽‍♂️🚶🏽‍♀️

Checklists

Draft Checklist

Merge Checklist

Issue(s) closed

Docs

Any docs updates needed?

Each EventGroup previously held two redundant structures: an
events: Map<string, WorkflowEvent> (primary storage) and an
eventIds: Set<string> (for O(1) has() checks). For a 40k-event
workflow this meant allocating ~20k Map objects (~700 bytes each)
and ~20k Set objects (~300 bytes each) — around 20MB of overhead
on top of the actual event data.
Replace both with a single eventList: WorkflowEvent[] as the
primary storage. Groups have 1–5 events in practice so linear
search (find/some) is O(1), and array push is cheaper than
Map.set + Set.add combined. Also simplify the closure-cached
eventList/links getters: eventList is now a plain property, links
iterates the array directly.
Update isEventGroup to discriminate on 'eventList' instead of
'events'. This was the key invariant that tests depended on:
isEventGroup returning false for every group caused
eventOrGroupIsFailureOrTimedOut, eventOrGroupIsCanceled, and
eventOrGroupIsTerminated to silently fall through to the raw-event
path (which always returned false for group objects). Test fixtures
that built mock EventGroups with an events: [] array were also
updated to use eventList: [] to match the new shape.
…tEvent

buildGroupIndex: one pass over filteredGroups builds a Map<eventId,
EventGroup> so any event→group lookup is O(1) instead of O(groups ×
events-per-group). Updated every call site that previously did
groups.find(g => g.eventList.some(...)) to use the index: history-graph,
event-summary-table, workflow-history-event, isMiddleEvent, and
getGroupForEventOrPendingEvent all accept Map | EventGroup[] and
fast-path on instanceof Map.
getLastEvent: removed the ID-scanning loop (which compared numeric event
IDs to find the maximum) and replaced it with eventList[eventList.length - 1].
Events are always appended in ascending-ID order by addToExistingGroup so
the last element is always the most recent event.
Eager classification fields: isFailureOrTimedOut, isCanceled, isTerminated,
billableActions, and links were all getters that scanned or reduced over
eventList on every access. They are now plain fields initialized from the
first event in createGroupFor and updated by a new addEventToGroup helper
called on each push in addToExistingGroup. Read cost drops from O(events-
per-group) to a single field access, which matters because these are read
from the SVG render path for every visible row.
@GiantRobots GiantRobots requested a review from a team as a code owner June 19, 2026 16:24
@vercel

vercel Bot commented Jun 19, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
holocene Ready Ready Preview, Comment Jun 20, 2026 12:19am

Request Review

@@ -28,9 +29,9 @@
<PendingNexusOperationCard operation={group.pendingNexusOperation} />
{/if}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • ⚠️ 'group' is possibly 'undefined'.

return group?.eventIds?.has(hoveredEventId);
return group?.eventList?.some((e) => e.id === hoveredEventId);
};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • ⚠️ Parameter 'group' implicitly has an 'any' type.
  • ⚠️ Parameter 'hoveredEventId' implicitly has an 'any' type.

return group?.eventList?.some((e) => e.id === hoveredEventId);
};

onMount(async () => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • ⚠️ Parameter 'e' implicitly has an 'any' type.

{@const group = getGroupForEventOrPendingEvent(allGroups, event)}
{@const group = getGroupForEventOrPendingEvent(groupIndex, event)}
<HistoryGraphRowVisual
{event}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • ⚠️ Type 'EventGroup | undefined' is not assignable to type 'EventGroup'.

_textWidthCache.set(cacheKey, width);
return width;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • ⚠️ Type 'SVGTextElement | undefined' is not assignable to type 'SVGTextElement'.


expect(group.events.size).toBe(2);
expect(group.events.get(completedEvent.id)).toBe(completedEvent);
expect(group.eventList.length).toBe(2);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • ⚠️ 'group' is possibly 'undefined'.

@@ -140,8 +144,10 @@ describe('groupEvents', () => {

const group = groups.find(({ id }) => id === scheduledEvent.id);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • ⚠️ 'group' is possibly 'undefined'.


expect(group.events.size).toBe(2);
expect(group.events.get(completedEvent.id)).toBe(completedEvent);
expect(group.eventList.length).toBe(2);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • ⚠️ 'group' is possibly 'undefined'.

const id = getGroupId(event);
const group = createEventGroup(event);

const pa = isActivityTaskScheduledEvent(event)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • ⚠️ 'event.activityTaskScheduledEventAttributes' is possibly 'null' or 'undefined'.
  • ⚠️ Argument of type 'string | null | undefined' is not assignable to parameter of type 'string'.

import { fetchAllEventsBidirectional } from '$lib/services/events-service';
import {
currentEventHistory,
fullEventHistory,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • ⚠️ Module '"$lib/stores/events"' has no exported member 'loadedWorkflowKey'.

@temporal-cicd

temporal-cicd Bot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor
Warnings
⚠️

📊 Strict Mode: 68 errors in 18 files (7.6% of 894 total)

src/lib/services/events-service.ts (11)
  • L76:43: Argument of type 'EventSortOrder | undefined' is not assignable to parameter of type 'EventSortOrder'.
  • L79:4: Argument of type '(token: string) => Promise' is not assignable to parameter of type '(token?: NextPageToken | undefined) => Promise'.
  • L89:18: Property 'history' does not exist on type 'WithoutNextPageToken'.
  • L109:20: Parameter 'full' implicitly has an 'any' type.
  • L109:26: Parameter 'current' implicitly has an 'any' type.
  • L115:19: Parameter 'e' implicitly has an 'any' type.
  • L129:4: Argument of type '(token: string) => Promise' is not assignable to parameter of type '(token?: NextPageToken | undefined) => Promise'.
  • L143:17: Property 'history' does not exist on type 'WithoutNextPageToken'.
  • L144:50: Property 'history' does not exist on type 'WithoutNextPageToken'.
  • L155:28: No overload matches this call.
  • L196:6: No overload matches this call.
src/lib/utilities/format-time.ts (3)
  • L177:34: Argument of type 'Duration | null' is not assignable to parameter of type 'string | Duration'.
  • L203:34: Argument of type 'Duration | null' is not assignable to parameter of type 'string | Duration'.
  • L284:17: Type 'undefined' is not assignable to type 'string'.
src/lib/models/event-groups/index.ts (2)
  • L52:23: 'event.activityTaskScheduledEventAttributes' is possibly 'null' or 'undefined'.
  • L52:23: Argument of type 'string | null | undefined' is not assignable to parameter of type 'string'.
src/lib/models/event-groups/create-event-group.ts (2)
  • L123:61: Function lacks ending return statement and return type does not include 'undefined'.
  • L154:3: Function lacks ending return statement and return type does not include 'undefined'.
src/lib/services/grouped-event-buffer.ts (1)
  • L508:8: Argument of type 'string | null | undefined' is not assignable to parameter of type 'string'.
src/lib/models/event-groups/group-events.test.ts (6)
  • L92:11: 'group' is possibly 'undefined'.
  • L132:11: 'group' is possibly 'undefined'.
  • L133:11: 'group' is possibly 'undefined'.
  • L146:11: 'group' is possibly 'undefined'.
  • L147:11: 'group' is possibly 'undefined'.
  • L170:36: Conversion of type 'undefined' to type 'CommonHistoryEvent' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.
src/lib/services/workflow-event-fetch.ts (1)
  • L10:2: Module '"$lib/stores/events"' has no exported member 'loadedWorkflowKey'.
src/lib/holocene/code-block.svelte (6)
  • L154:32: 'editorView.contentHeight' is possibly 'undefined'.
  • L174:24: Type 'number | boolean' is not assignable to type 'boolean'.
  • L182:23: Type 'number | undefined' is not assignable to type 'number'.
  • L182:34: Type 'number | undefined' is not assignable to type 'number'.
  • L194:8: 'editorView' is possibly 'undefined'.
  • L327:32: Type 'boolean | 0' is not assignable to type 'boolean | undefined'.
src/lib/components/payload/payload-code-block.svelte (1)
  • L77:43: 'data.payloads' is possibly 'null' or 'undefined'.
src/lib/components/event/event-card.svelte (11)
  • L142:37: Type 'string | null | undefined' is not assignable to type 'string'.
  • L142:48: 'link.workflowEvent' is possibly 'null' or 'undefined'.
  • L150:6: Type 'string | null | undefined' is not assignable to type 'string'.
  • L150:15: 'link.workflowEvent' is possibly 'null' or 'undefined'.
  • L153:10: 'link.workflowEvent' is possibly 'null' or 'undefined'.
  • L177:19: Parameter 'key' implicitly has an 'any' type.
  • L177:24: Parameter 'value' implicitly has an 'any' type.
  • L227:15: Parameter 'key' implicitly has an 'any' type.
  • L227:20: Parameter 'value' implicitly has an 'any' type.
  • L247:18: Parameter 'key' implicitly has an 'any' type.
  • L247:23: Parameter 'value' implicitly has an 'any' type.
src/lib/components/event/event-details-full.svelte (1)
  • L30:11: 'group' is possibly 'undefined'.
src/lib/components/event/event-summary-row.svelte (6)
  • L137:6: Argument of type 'string | undefined' is not assignable to parameter of type 'string'.
  • L174:23: Parameter 'event' implicitly has an 'any' type.
  • L189:30: Parameter 'group' implicitly has an 'any' type.
  • L189:37: Parameter 'hoveredEventId' implicitly has an 'any' type.
  • L190:35: Parameter 'e' implicitly has an 'any' type.
  • L339:16: Type 'ITimestamp | null | undefined' is not assignable to type 'ITimestamp'.
src/lib/components/lines-and-dots/svg/history-graph.svelte (1)
  • L77:11: Type 'EventGroup | undefined' is not assignable to type 'EventGroup'.
src/lib/components/lines-and-dots/svg/group-details-row.svelte (5)
  • L69:17: 'group.pendingActivity.attempt' is possibly 'null' or 'undefined'.
  • L118:14: Type 'string | null | undefined' is not assignable to type 'string'.
  • L118:26: 'childWorkflowStartedEvent.attributes.workflowExecution' is possibly 'null' or 'undefined'.
  • L120:14: Type 'string | null | undefined' is not assignable to type 'string | undefined'.
  • L120:21: 'childWorkflowStartedEvent.attributes.workflowExecution' is possibly 'null' or 'undefined'.
src/lib/components/lines-and-dots/svg/text.svelte (3)
  • L70:6: Type 'SVGTextElement | undefined' is not assignable to type 'SVGTextElement'.
  • L87:45: 'config' is possibly 'undefined'.
  • L101:4: Type 'TimelineIconName | undefined' is not assignable to type 'TimelineIconName'.
src/lib/components/lines-and-dots/svg/timeline-graph-row.svelte (5)
  • L141:20: 'distance' is possibly 'null'.
  • L141:31: 'workflowDistance' is possibly 'null'.
  • L152:20: 'distance' is possibly 'null'.
  • L152:31: 'workflowDistance' is possibly 'null'.
  • L297:12: 'pendingActivity.attempt' is possibly 'null' or 'undefined'.
src/lib/components/lines-and-dots/svg/workflow-row.svelte (2)
  • L48:26: Type 'WorkflowStatus' is not assignable to type 'string | undefined'.
  • L57:24: Type 'WorkflowStatus' is not assignable to type 'string | undefined'.
src/lib/pages/workflow-history-event.svelte (1)
  • L71:12: 'workflow' is possibly 'null'.

Generated by 🚫 dangerJS against 4de183d

const initial = group.initialEvent;

if (isActivityTaskScheduledEvent(initial)) {
const pa = byActivityId.get(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • ⚠️ Argument of type 'string | null | undefined' is not assignable to parameter of type 'string'.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant