Skip to content

fix(core): define RunEvent schema and update ApiClient validation#3220

Open
bharathkumar39293 wants to merge 6 commits intotriggerdotdev:mainfrom
bharathkumar39293:fix/run-event-schema-v3
Open

fix(core): define RunEvent schema and update ApiClient validation#3220
bharathkumar39293 wants to merge 6 commits intotriggerdotdev:mainfrom
bharathkumar39293:fix/run-event-schema-v3

Conversation

@bharathkumar39293
Copy link
Contributor

Resolves the internal TODO in

ApiClient
regarding missing schema validation for task run events.

✅ Checklist
I have followed every step in the contributing guide
The PR title follows the convention.
I ran and tested the code works
Technical Cost/Benefit Analysis
Benefit:

Reliability: Replaces z.any() with a strict Zod schema, preventing the SDK from returning invalid or unexpected data formats.
Safety: Addresses two critical edge cases identified during development:
Wrapper Handling: The API returns { events: [...] }. This PR adds the

ListRunEventsResponse
wrapper.
Nullable parentId: Supports null for root spans (stored as null in DB).
Integration: Ensures consistency for tools like the MCP server.
Cost/Risk:

Low Risk: Localized change to @trigger.dev/core. Highly decoupled from other services.
Testing
Unit tests in

packages/core/src/v3/schemas/api-type.test.ts
verify:

Valid event parsing & date coercion.
Failure on invalid data.
Handling of null and undefined for parentId.
Handling of the { events: [...] } response wrapper.
Changelog
@trigger.dev/core: Added

RunEvent
and

ListRunEventsResponse
Zod schemas.
@trigger.dev/core: Updated ApiClient.listRunEvents to use strict validation.

@changeset-bot
Copy link

changeset-bot bot commented Mar 14, 2026

🦋 Changeset detected

Latest commit: fd2f823

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 28 packages
Name Type
@trigger.dev/core Patch
@trigger.dev/build Patch
trigger.dev Patch
@trigger.dev/python Patch
@trigger.dev/redis-worker Patch
@trigger.dev/schema-to-json Patch
@trigger.dev/sdk Patch
@internal/cache Patch
@internal/clickhouse Patch
@internal/redis Patch
@internal/replication Patch
@internal/run-engine Patch
@internal/schedule-engine Patch
@internal/testcontainers Patch
@internal/tracing Patch
@internal/tsql Patch
@internal/zod-worker Patch
d3-chat Patch
references-d3-openai-agents Patch
references-nextjs-realtime Patch
references-realtime-hooks-test Patch
references-realtime-streams Patch
references-telemetry Patch
@internal/sdk-compat-tests Patch
@trigger.dev/react-hooks Patch
@trigger.dev/rsc Patch
@trigger.dev/database Patch
@trigger.dev/otlp-importer Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 14, 2026

Walkthrough

Adds event-driven schemas: TaskEventLevel enum, NanosecondTimestampSchema (coerces nanosecond/millisecond/string inputs to Date), RunEvent (fields: spanId, parentId, runId, message, style, startTime, duration, isError, isPartial, isCancelled, level, events, kind, attemptNumber, taskSlug) and ListRunEventsResponse (events array). Exports types for these schemas. Replaces a previous generic response schema in ApiClient.listRunEvents with ListRunEventsResponse. Tests added/expanded to validate RunEvent and ListRunEventsResponse parsing, date coercion, and optional/null behaviors.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main changes: defining a RunEvent schema and updating ApiClient validation to use it instead of z.any().
Description check ✅ Passed The PR description covers all required sections from the template with comprehensive technical details, testing information, and changelog entries.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
packages/core/src/v3/apiClient/index.ts (1)

31-31: Consider removing unused import.

RunEvent is imported on line 46 but doesn't appear to be used directly in this file. Only ListRunEventsResponse is used at line 705. The RunEvent type is already part of ListRunEventsResponse.events, so consumers can access it via the response type if needed.

🧹 Proposed fix to remove unused import
 import {
   AddTagsRequestBody,
   ApiDeploymentListOptions,
   ApiDeploymentListResponseItem,
   ApiDeploymentListSearchParams,
   AppendToStreamResponseBody,
   BatchItemNDJSON,
   BatchTaskRunExecutionResult,
   BatchTriggerTaskV3RequestBody,
   BatchTriggerTaskV3Response,
   CanceledRunResponse,
   CompleteWaitpointTokenRequestBody,
   CompleteWaitpointTokenResponseBody,
   CreateBatchRequestBody,
   CreateBatchResponse,
   CreateEnvironmentVariableRequestBody,
   CreateInputStreamWaitpointRequestBody,
   CreateInputStreamWaitpointResponseBody,
   CreateScheduleOptions,
   CreateStreamResponseBody,
   CreateUploadPayloadUrlResponseBody,
   CreateWaitpointTokenRequestBody,
   CreateWaitpointTokenResponseBody,
   DeletedScheduleObject,
   EnvironmentVariableResponseBody,
   EnvironmentVariableWithSecret,
   ListQueueOptions,
   ListRunEventsResponse,
   ListRunResponseItem,
   ListScheduleOptions,
   QueueItem,
   QueueTypeName,
   QueryExecuteRequestBody,
   QueryExecuteResponseBody,
   QueryExecuteCSVResponseBody,
   ReplayRunResponse,
   RescheduleRunRequestBody,
   ResetIdempotencyKeyResponse,
   RetrieveBatchV2Response,
   RetrieveQueueParam,
   RetrieveRunResponse,
   RetrieveRunTraceResponseBody,
-  RunEvent,
   ScheduleObject,
   SendInputStreamResponseBody,
   StreamBatchItemsResponse,

Also applies to: 46-46

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/core/src/v3/apiClient/index.ts` at line 31, Remove the unused
RunEvent import from the module: locate the import list that currently includes
RunEvent (alongside ListRunEventsResponse) and delete only RunEvent, leaving
ListRunEventsResponse intact; confirm no other references to the RunEvent
identifier exist in this file (consumers can access it via
ListRunEventsResponse.events) and run a typecheck to ensure the removal is safe.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@packages/core/src/v3/apiClient/index.ts`:
- Line 31: Remove the unused RunEvent import from the module: locate the import
list that currently includes RunEvent (alongside ListRunEventsResponse) and
delete only RunEvent, leaving ListRunEventsResponse intact; confirm no other
references to the RunEvent identifier exist in this file (consumers can access
it via ListRunEventsResponse.events) and run a typecheck to ensure the removal
is safe.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 1cd5cb80-8c72-45a8-855e-ee9ff0ad7de8

📥 Commits

Reviewing files that changed from the base of the PR and between 7672e8d and 0d361c8.

📒 Files selected for processing (4)
  • .changeset/define-runevent-schema.md
  • packages/core/src/v3/apiClient/index.ts
  • packages/core/src/v3/schemas/api-type.test.ts
  • packages/core/src/v3/schemas/api.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (13)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (3, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (7, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (1, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (5, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (1, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (5, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (2, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (4, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (7, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (6, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (3, 8)
  • GitHub Check: units / packages / 🧪 Unit Tests: Packages (1, 1)
  • GitHub Check: typecheck / typecheck
🧰 Additional context used
📓 Path-based instructions (12)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{ts,tsx}: Use types over interfaces for TypeScript
Avoid using enums; prefer string unions or const objects instead

**/*.{ts,tsx}: Use task export syntax: export const myTask = task({ id: 'my-task', run: async (payload) => { ... } })
Use Run Engine 2.0 (@internal/run-engine) and redis-worker for all new work - avoid DEPRECATED zodworker (Graphile-worker wrapper)
Prisma 6.14.0 client and schema use PostgreSQL in internal-packages/database - import only from Prisma client

Files:

  • packages/core/src/v3/schemas/api-type.test.ts
  • packages/core/src/v3/apiClient/index.ts
  • packages/core/src/v3/schemas/api.ts
{packages/core,apps/webapp}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use zod for validation in packages/core and apps/webapp

Files:

  • packages/core/src/v3/schemas/api-type.test.ts
  • packages/core/src/v3/apiClient/index.ts
  • packages/core/src/v3/schemas/api.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use function declarations instead of default exports

Files:

  • packages/core/src/v3/schemas/api-type.test.ts
  • packages/core/src/v3/apiClient/index.ts
  • packages/core/src/v3/schemas/api.ts
**/*.{test,spec}.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use vitest for all tests in the Trigger.dev repository

Files:

  • packages/core/src/v3/schemas/api-type.test.ts
**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/otel-metrics.mdc)

**/*.ts: When creating or editing OTEL metrics (counters, histograms, gauges), ensure metric attributes have low cardinality by using only enums, booleans, bounded error codes, or bounded shard IDs
Do not use high-cardinality attributes in OTEL metrics such as UUIDs/IDs (envId, userId, runId, projectId, organizationId), unbounded integers (itemCount, batchSize, retryCount), timestamps (createdAt, startTime), or free-form strings (errorMessage, taskName, queueName)
When exporting OTEL metrics via OTLP to Prometheus, be aware that the exporter automatically adds unit suffixes to metric names (e.g., 'my_duration_ms' becomes 'my_duration_ms_milliseconds', 'my_counter' becomes 'my_counter_total'). Account for these transformations when writing Grafana dashboards or Prometheus queries

Files:

  • packages/core/src/v3/schemas/api-type.test.ts
  • packages/core/src/v3/apiClient/index.ts
  • packages/core/src/v3/schemas/api.ts
**/*.{js,ts,jsx,tsx,json,md,yaml,yml}

📄 CodeRabbit inference engine (AGENTS.md)

Format code using Prettier before committing

Files:

  • packages/core/src/v3/schemas/api-type.test.ts
  • packages/core/src/v3/apiClient/index.ts
  • packages/core/src/v3/schemas/api.ts
**/*.test.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.test.{ts,tsx,js,jsx}: Test files should live beside the files under test and use descriptive describe and it blocks
Tests should avoid mocks or stubs and use the helpers from @internal/testcontainers when Redis or Postgres are needed
Use vitest for running unit tests

Files:

  • packages/core/src/v3/schemas/api-type.test.ts
packages/core/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (packages/core/CLAUDE.md)

Never import the root package (@trigger.dev/core). Always use subpath imports such as @trigger.dev/core/v3, @trigger.dev/core/v3/utils, @trigger.dev/core/logger, or @trigger.dev/core/schemas

Files:

  • packages/core/src/v3/schemas/api-type.test.ts
  • packages/core/src/v3/apiClient/index.ts
  • packages/core/src/v3/schemas/api.ts
**/*.test.{ts,tsx,js}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.test.{ts,tsx,js}: Use vitest exclusively for testing - never mock anything, use testcontainers instead
Place test files next to source files with naming convention: SourceFile.ts -> SourceFile.test.ts

Files:

  • packages/core/src/v3/schemas/api-type.test.ts
**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use testcontainers for Redis/PostgreSQL testing instead of mocks with redisTest, postgresTest, or containerTest helpers from @internal/testcontainers

Files:

  • packages/core/src/v3/schemas/api-type.test.ts
{packages,integrations}/**/*.{ts,tsx,js,json}

📄 CodeRabbit inference engine (CLAUDE.md)

When modifying public packages (packages/* or integrations/*), add a changeset using pnpm run changeset:add with default patch level for bug fixes and minor changes

Files:

  • packages/core/src/v3/schemas/api-type.test.ts
  • packages/core/src/v3/apiClient/index.ts
  • packages/core/src/v3/schemas/api.ts
**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx,js}: Always import from @trigger.dev/sdk for Trigger.dev tasks - never use @trigger.dev/sdk/v3 or deprecated client.defineJob
Import subpaths only from @trigger.dev/core, never import from root
Add crumbs as you write code using // @crumbs comments or // #region @crumbs blocks for agentcrumbs debug tracing

Files:

  • packages/core/src/v3/schemas/api-type.test.ts
  • packages/core/src/v3/apiClient/index.ts
  • packages/core/src/v3/schemas/api.ts
🧠 Learnings (25)
📓 Common learnings
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Use `schemaTask()` from `trigger.dev/sdk/v3` with Zod schema for payload validation
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Use `schemaTask()` from `trigger.dev/sdk/v3` with Zod schema for payload validation

Applied to files:

  • .changeset/define-runevent-schema.md
  • packages/core/src/v3/schemas/api.ts
📚 Learning: 2026-03-02T12:43:25.254Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: internal-packages/run-engine/CLAUDE.md:0-0
Timestamp: 2026-03-02T12:43:25.254Z
Learning: Applies to internal-packages/run-engine/src/engine/tests/**/*.test.ts : Implement tests for RunEngine in `src/engine/tests/` using testcontainers for Redis and PostgreSQL containerization

Applied to files:

  • packages/core/src/v3/schemas/api-type.test.ts
📚 Learning: 2026-01-15T10:48:02.687Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-15T10:48:02.687Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Use vitest for running unit tests

Applied to files:

  • packages/core/src/v3/schemas/api-type.test.ts
📚 Learning: 2025-11-27T16:26:37.432Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-27T16:26:37.432Z
Learning: Applies to **/*.{test,spec}.{ts,tsx} : Use vitest for all tests in the Trigger.dev repository

Applied to files:

  • packages/core/src/v3/schemas/api-type.test.ts
📚 Learning: 2026-01-15T10:48:02.687Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-15T10:48:02.687Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Test files should live beside the files under test and use descriptive `describe` and `it` blocks

Applied to files:

  • packages/core/src/v3/schemas/api-type.test.ts
📚 Learning: 2026-03-02T12:42:56.114Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: apps/webapp/CLAUDE.md:0-0
Timestamp: 2026-03-02T12:42:56.114Z
Learning: Applies to apps/webapp/app/v3/services/**/*.server.ts : When editing services that branch on `RunEngineVersion` to support both V1 and V2 (e.g., `cancelTaskRun.server.ts`, `batchTriggerV3.server.ts`), only modify V2 code paths

Applied to files:

  • packages/core/src/v3/apiClient/index.ts
📚 Learning: 2026-03-02T12:43:25.254Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: internal-packages/run-engine/CLAUDE.md:0-0
Timestamp: 2026-03-02T12:43:25.254Z
Learning: Applies to internal-packages/run-engine/src/engine/systems/**/*.ts : Integrate OpenTelemetry tracer and meter instrumentation in RunEngine systems for observability

Applied to files:

  • packages/core/src/v3/schemas/api.ts
📚 Learning: 2026-03-13T13:37:49.544Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-13T13:37:49.544Z
Learning: Applies to **/*.{ts,tsx} : Use task export syntax: export const myTask = task({ id: 'my-task', run: async (payload) => { ... } })

Applied to files:

  • packages/core/src/v3/schemas/api.ts
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Use `.withStreams()` to subscribe to realtime streams from task metadata in addition to run changes

Applied to files:

  • packages/core/src/v3/schemas/api.ts
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Subscribe to run updates using `runs.subscribeToRun()` for realtime monitoring of task execution

Applied to files:

  • packages/core/src/v3/schemas/api.ts
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Attach metadata to task runs using the metadata option when triggering, and access/update it inside runs using metadata functions

Applied to files:

  • packages/core/src/v3/schemas/api.ts
📚 Learning: 2026-03-13T13:37:49.544Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-13T13:37:49.544Z
Learning: Applies to {packages,integrations}/**/*.{ts,tsx,js,json} : When modifying public packages (packages/* or integrations/*), add a changeset using pnpm run changeset:add with default patch level for bug fixes and minor changes

Applied to files:

  • packages/core/src/v3/schemas/api.ts
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Export tasks with unique IDs within the project to enable proper task discovery and execution

Applied to files:

  • packages/core/src/v3/schemas/api.ts
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger.config.ts : Configure OpenTelemetry instrumentations and exporters in trigger.config.ts for enhanced logging

Applied to files:

  • packages/core/src/v3/schemas/api.ts
📚 Learning: 2026-03-13T13:37:49.544Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-13T13:37:49.544Z
Learning: Applies to **/*.{ts,tsx} : Use Run Engine 2.0 (internal/run-engine) and redis-worker for all new work - avoid DEPRECATED zodworker (Graphile-worker wrapper)

Applied to files:

  • packages/core/src/v3/schemas/api.ts
📚 Learning: 2026-03-02T12:42:56.114Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: apps/webapp/CLAUDE.md:0-0
Timestamp: 2026-03-02T12:42:56.114Z
Learning: Target Run Engine V2 for all new code; the `engineVersion.server.ts` file determines V1 vs V2 for a given environment

Applied to files:

  • packages/core/src/v3/schemas/api.ts
📚 Learning: 2025-11-27T16:26:58.661Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/webapp.mdc:0-0
Timestamp: 2025-11-27T16:26:58.661Z
Learning: Use the Run Engine 2.0 from `internal/run-engine` for new run lifecycle code in the webapp instead of the legacy run engine

Applied to files:

  • packages/core/src/v3/schemas/api.ts
📚 Learning: 2026-03-02T12:42:56.114Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: apps/webapp/CLAUDE.md:0-0
Timestamp: 2026-03-02T12:42:56.114Z
Learning: V1-only legacy code is located in `app/v3/marqs/`, `app/v3/legacyRunEngineWorker.server.ts`, `app/v3/services/triggerTaskV1.server.ts`, `app/v3/services/cancelTaskRunV1.server.ts`, `app/v3/authenticatedSocketConnection.server.ts`, and `app/v3/sharedSocketConnection.ts`

Applied to files:

  • packages/core/src/v3/schemas/api.ts
📚 Learning: 2026-03-02T12:42:56.114Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: apps/webapp/CLAUDE.md:0-0
Timestamp: 2026-03-02T12:42:56.114Z
Learning: All run lifecycle operations (triggering, completing, cancelling, etc.) should be performed through the singleton run engine instance in `app/v3/runEngine.server.ts` via service calls

Applied to files:

  • packages/core/src/v3/schemas/api.ts
📚 Learning: 2026-03-02T12:43:17.177Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: internal-packages/database/CLAUDE.md:0-0
Timestamp: 2026-03-02T12:43:17.177Z
Learning: New code should always target Prisma RunEngineVersion V2 (run-engine + redis-worker), not V1 (legacy MarQS + Graphile)

Applied to files:

  • packages/core/src/v3/schemas/api.ts
📚 Learning: 2026-03-02T12:42:56.114Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: apps/webapp/CLAUDE.md:0-0
Timestamp: 2026-03-02T12:42:56.114Z
Learning: Applies to apps/webapp/app/v3/*Worker.server.ts : New background job workers should use `trigger.dev/redis-worker` (e.g., `commonWorker.server.ts`, `alertsWorker.server.ts`, `batchTriggerWorker.server.ts`), not zodworker or graphile-worker

Applied to files:

  • packages/core/src/v3/schemas/api.ts
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Export every task, including subtasks

Applied to files:

  • packages/core/src/v3/schemas/api.ts
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Use the `task()` function from `trigger.dev/sdk/v3` to define tasks with id and run properties

Applied to files:

  • packages/core/src/v3/schemas/api.ts
📚 Learning: 2025-11-27T16:26:37.432Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-27T16:26:37.432Z
Learning: Applies to {packages/core,apps/webapp}/**/*.{ts,tsx} : Use zod for validation in packages/core and apps/webapp

Applied to files:

  • packages/core/src/v3/schemas/api.ts
🔇 Additional comments (9)
packages/core/src/v3/schemas/api.ts (4)

12-13: LGTM!

The imports for TaskEventStyle and SpanEvents are correctly added to support the new RunEvent schema definition.


1644-1645: LGTM!

TaskEventLevel uses z.enum() which produces a TypeScript string union type, consistent with other similar definitions in this file (e.g., RunStatus, AttemptStatus, BatchStatus).


1647-1664: LGTM!

The RunEvent schema is well-structured:

  • Uses .nullish() for parentId to correctly handle root spans where parentId may be null from the DB
  • Uses z.coerce.date() for startTime, consistent with other date fields in this file
  • Properly references existing schemas (TaskEventStyle, TaskEventLevel, SpanEvents)

1666-1670: LGTM!

The ListRunEventsResponse wrapper correctly encapsulates the events array in an object, providing a proper response shape that can be extended in the future without breaking changes.

.changeset/define-runevent-schema.md (1)

1-5: LGTM!

The changeset is properly formatted with patch level, which is appropriate for this bug fix that adds strict schema validation to replace z.any().

packages/core/src/v3/apiClient/index.ts (1)

703-713: LGTM!

The listRunEvents method now uses ListRunEventsResponse schema instead of z.any(), providing strict validation for the API response. This is the core fix for the internal TODO mentioned in the PR objectives.

packages/core/src/v3/schemas/api-type.test.ts (3)

2-2: LGTM!

Imports correctly added for the new schemas to be tested.


143-200: LGTM!

Comprehensive test coverage for RunEvent schema:

  • Valid event parsing with date coercion verification
  • Missing required field detection
  • Invalid enum value rejection
  • Both undefined (missing) and null parentId handling

The tests align well with the schema definition and PR objectives.


202-233: LGTM!

Good test coverage for ListRunEventsResponse:

  • Validates the wrapper object structure
  • Correctly verifies that a plain array fails, ensuring the { events: [...] } wrapper is required

The tests confirm the API response shape change is properly enforced.

@bharathkumar39293 bharathkumar39293 marked this pull request as ready for review March 14, 2026 16:19
Copy link
Contributor

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

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

Devin Review found 4 potential issues.

View 1 additional finding in Devin Review.

Open in Devin Review

isCancelled: z.boolean(),
level: TaskEventLevel,
events: SpanEvents.optional(),
kind: z.string(),
Copy link
Contributor

@devin-ai-integration devin-ai-integration bot Mar 14, 2026

Choose a reason for hiding this comment

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

📝 Info: ClickHouse getRunEvents hardcodes kind to 'UNSPECIFIED' and omits taskSlug

The ClickHouse #spanSummaryToRunPreparedEvent (apps/webapp/app/v3/eventRepository/clickhouseEventRepository.server.ts:1908-1925) hardcodes kind: "UNSPECIFIED" and does not include taskSlug. The RunEvent schema handles both: kind is z.string() so "UNSPECIFIED" is valid, and taskSlug is .optional(). The Prisma-based getRunEvents (apps/webapp/app/v3/eventRepository/eventRepository.server.ts:723-726) filters out kind === "UNSPECIFIED" events before returning, but the ClickHouse version doesn't—so ClickHouse-backed responses will have all events with kind: "UNSPECIFIED". This is pre-existing behavior and not caused by this PR, but it means the kind field is not very meaningful for ClickHouse-sourced events.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/core/src/v3/schemas/api.ts`:
- Around line 1646-1666: NanosecondTimestampSchema's transform can return
invalid Dates and never accepts Date inputs; update the schema to include
z.date() in the union so Date values reach the transform (or handle them via a
preprocess) and then validate the transformed value by adding a refine that
checks !isNaN(date.getTime()) with a clear error message; reference
NanosecondTimestampSchema and ensure the transform still handles 19- and
13-digit strings but add the post-transform validation (or replace transform
with preprocess+parse and then z.date() to guarantee a validated Date).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 2b895805-270f-4e5f-8479-59c111f5f1db

📥 Commits

Reviewing files that changed from the base of the PR and between 0d361c8 and fd2f823.

📒 Files selected for processing (2)
  • packages/core/src/v3/schemas/api-type.test.ts
  • packages/core/src/v3/schemas/api.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: units / internal / 📊 Merge Reports
  • GitHub Check: units / packages / 📊 Merge Reports
  • GitHub Check: typecheck / typecheck
🧰 Additional context used
📓 Path-based instructions (12)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{ts,tsx}: Use types over interfaces for TypeScript
Avoid using enums; prefer string unions or const objects instead

**/*.{ts,tsx}: Use task export syntax: export const myTask = task({ id: 'my-task', run: async (payload) => { ... } })
Use Run Engine 2.0 (@internal/run-engine) and redis-worker for all new work - avoid DEPRECATED zodworker (Graphile-worker wrapper)
Prisma 6.14.0 client and schema use PostgreSQL in internal-packages/database - import only from Prisma client

Files:

  • packages/core/src/v3/schemas/api-type.test.ts
  • packages/core/src/v3/schemas/api.ts
{packages/core,apps/webapp}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use zod for validation in packages/core and apps/webapp

Files:

  • packages/core/src/v3/schemas/api-type.test.ts
  • packages/core/src/v3/schemas/api.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use function declarations instead of default exports

Files:

  • packages/core/src/v3/schemas/api-type.test.ts
  • packages/core/src/v3/schemas/api.ts
**/*.{test,spec}.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use vitest for all tests in the Trigger.dev repository

Files:

  • packages/core/src/v3/schemas/api-type.test.ts
**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/otel-metrics.mdc)

**/*.ts: When creating or editing OTEL metrics (counters, histograms, gauges), ensure metric attributes have low cardinality by using only enums, booleans, bounded error codes, or bounded shard IDs
Do not use high-cardinality attributes in OTEL metrics such as UUIDs/IDs (envId, userId, runId, projectId, organizationId), unbounded integers (itemCount, batchSize, retryCount), timestamps (createdAt, startTime), or free-form strings (errorMessage, taskName, queueName)
When exporting OTEL metrics via OTLP to Prometheus, be aware that the exporter automatically adds unit suffixes to metric names (e.g., 'my_duration_ms' becomes 'my_duration_ms_milliseconds', 'my_counter' becomes 'my_counter_total'). Account for these transformations when writing Grafana dashboards or Prometheus queries

Files:

  • packages/core/src/v3/schemas/api-type.test.ts
  • packages/core/src/v3/schemas/api.ts
**/*.{js,ts,jsx,tsx,json,md,yaml,yml}

📄 CodeRabbit inference engine (AGENTS.md)

Format code using Prettier before committing

Files:

  • packages/core/src/v3/schemas/api-type.test.ts
  • packages/core/src/v3/schemas/api.ts
**/*.test.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.test.{ts,tsx,js,jsx}: Test files should live beside the files under test and use descriptive describe and it blocks
Tests should avoid mocks or stubs and use the helpers from @internal/testcontainers when Redis or Postgres are needed
Use vitest for running unit tests

Files:

  • packages/core/src/v3/schemas/api-type.test.ts
packages/core/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (packages/core/CLAUDE.md)

Never import the root package (@trigger.dev/core). Always use subpath imports such as @trigger.dev/core/v3, @trigger.dev/core/v3/utils, @trigger.dev/core/logger, or @trigger.dev/core/schemas

Files:

  • packages/core/src/v3/schemas/api-type.test.ts
  • packages/core/src/v3/schemas/api.ts
**/*.test.{ts,tsx,js}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.test.{ts,tsx,js}: Use vitest exclusively for testing - never mock anything, use testcontainers instead
Place test files next to source files with naming convention: SourceFile.ts -> SourceFile.test.ts

Files:

  • packages/core/src/v3/schemas/api-type.test.ts
**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use testcontainers for Redis/PostgreSQL testing instead of mocks with redisTest, postgresTest, or containerTest helpers from @internal/testcontainers

Files:

  • packages/core/src/v3/schemas/api-type.test.ts
{packages,integrations}/**/*.{ts,tsx,js,json}

📄 CodeRabbit inference engine (CLAUDE.md)

When modifying public packages (packages/* or integrations/*), add a changeset using pnpm run changeset:add with default patch level for bug fixes and minor changes

Files:

  • packages/core/src/v3/schemas/api-type.test.ts
  • packages/core/src/v3/schemas/api.ts
**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx,js}: Always import from @trigger.dev/sdk for Trigger.dev tasks - never use @trigger.dev/sdk/v3 or deprecated client.defineJob
Import subpaths only from @trigger.dev/core, never import from root
Add crumbs as you write code using // @crumbs comments or // #region @crumbs blocks for agentcrumbs debug tracing

Files:

  • packages/core/src/v3/schemas/api-type.test.ts
  • packages/core/src/v3/schemas/api.ts
🧠 Learnings (29)
📓 Common learnings
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Use `schemaTask()` from `trigger.dev/sdk/v3` with Zod schema for payload validation
📚 Learning: 2026-03-02T12:43:25.254Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: internal-packages/run-engine/CLAUDE.md:0-0
Timestamp: 2026-03-02T12:43:25.254Z
Learning: Applies to internal-packages/run-engine/src/engine/tests/**/*.test.ts : Implement tests for RunEngine in `src/engine/tests/` using testcontainers for Redis and PostgreSQL containerization

Applied to files:

  • packages/core/src/v3/schemas/api-type.test.ts
📚 Learning: 2026-01-15T10:48:02.687Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-15T10:48:02.687Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Use vitest for running unit tests

Applied to files:

  • packages/core/src/v3/schemas/api-type.test.ts
📚 Learning: 2025-11-27T16:26:37.432Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-27T16:26:37.432Z
Learning: Applies to **/*.{test,spec}.{ts,tsx} : Use vitest for all tests in the Trigger.dev repository

Applied to files:

  • packages/core/src/v3/schemas/api-type.test.ts
📚 Learning: 2026-01-15T10:48:02.687Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-15T10:48:02.687Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Test files should live beside the files under test and use descriptive `describe` and `it` blocks

Applied to files:

  • packages/core/src/v3/schemas/api-type.test.ts
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Use `schemaTask()` from `trigger.dev/sdk/v3` with Zod schema for payload validation

Applied to files:

  • packages/core/src/v3/schemas/api.ts
📚 Learning: 2026-03-02T12:43:25.254Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: internal-packages/run-engine/CLAUDE.md:0-0
Timestamp: 2026-03-02T12:43:25.254Z
Learning: Applies to internal-packages/run-engine/src/engine/systems/**/*.ts : Integrate OpenTelemetry tracer and meter instrumentation in RunEngine systems for observability

Applied to files:

  • packages/core/src/v3/schemas/api.ts
📚 Learning: 2026-03-13T13:37:49.544Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-13T13:37:49.544Z
Learning: Applies to **/*.{ts,tsx} : Use task export syntax: export const myTask = task({ id: 'my-task', run: async (payload) => { ... } })

Applied to files:

  • packages/core/src/v3/schemas/api.ts
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Attach metadata to task runs using the metadata option when triggering, and access/update it inside runs using metadata functions

Applied to files:

  • packages/core/src/v3/schemas/api.ts
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Use `.withStreams()` to subscribe to realtime streams from task metadata in addition to run changes

Applied to files:

  • packages/core/src/v3/schemas/api.ts
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Subscribe to run updates using `runs.subscribeToRun()` for realtime monitoring of task execution

Applied to files:

  • packages/core/src/v3/schemas/api.ts
📚 Learning: 2026-03-13T13:37:49.544Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-13T13:37:49.544Z
Learning: Applies to {packages,integrations}/**/*.{ts,tsx,js,json} : When modifying public packages (packages/* or integrations/*), add a changeset using pnpm run changeset:add with default patch level for bug fixes and minor changes

Applied to files:

  • packages/core/src/v3/schemas/api.ts
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Export tasks with unique IDs within the project to enable proper task discovery and execution

Applied to files:

  • packages/core/src/v3/schemas/api.ts
📚 Learning: 2026-03-13T13:37:49.544Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-13T13:37:49.544Z
Learning: Applies to **/*.{ts,tsx} : Prisma 6.14.0 client and schema use PostgreSQL in internal-packages/database - import only from Prisma client

Applied to files:

  • packages/core/src/v3/schemas/api.ts
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Use `trigger.dev/sdk/v3` for all imports in Trigger.dev tasks

Applied to files:

  • packages/core/src/v3/schemas/api.ts
📚 Learning: 2026-03-13T13:42:47.903Z
Learnt from: ericallam
Repo: triggerdotdev/trigger.dev PR: 3213
File: apps/webapp/app/routes/admin.api.v1.llm-models.$modelId.ts:40-43
Timestamp: 2026-03-13T13:42:47.903Z
Learning: In `apps/webapp/app/routes/admin.api.v1.llm-models.$modelId.ts` and `apps/webapp/app/routes/admin.api.v1.llm-models.ts`, the `startDate` field in `UpdateModelSchema` and `CreateModelSchema` intentionally uses `z.string().optional()` (or `.nullable().optional()`) without strict ISO datetime validation. Invalid date strings are rejected at the Prisma/DB layer. This is acceptable because these are admin-only API routes protected by Personal Access Token (PAT) authentication and are not user-facing.

Applied to files:

  • packages/core/src/v3/schemas/api.ts
📚 Learning: 2026-01-28T14:15:15.011Z
Learnt from: matt-aitken
Repo: triggerdotdev/trigger.dev PR: 2953
File: apps/webapp/app/components/runs/v3/SharedFilters.tsx:441-452
Timestamp: 2026-01-28T14:15:15.011Z
Learning: In apps/webapp/app/components/runs/v3/SharedFilters.tsx, the maxPeriodDays limit for date ranges should only check the from date (via dateRangeToDays(fromValue)) because it enforces data retention limits—how far back in history queries can reach. The to date is irrelevant for retention-based limits.

Applied to files:

  • packages/core/src/v3/schemas/api.ts
📚 Learning: 2025-08-14T10:09:02.528Z
Learnt from: nicktrn
Repo: triggerdotdev/trigger.dev PR: 2390
File: internal-packages/run-engine/src/engine/index.ts:466-467
Timestamp: 2025-08-14T10:09:02.528Z
Learning: In the triggerdotdev/trigger.dev codebase, it's acceptable to pass `string | undefined` types directly to Prisma operations (both create and update). The codebase consistently uses this pattern and the team is comfortable with how Prisma handles undefined values.

Applied to files:

  • packages/core/src/v3/schemas/api.ts
📚 Learning: 2025-07-12T18:06:04.133Z
Learnt from: matt-aitken
Repo: triggerdotdev/trigger.dev PR: 2264
File: apps/webapp/app/services/runsRepository.server.ts:172-174
Timestamp: 2025-07-12T18:06:04.133Z
Learning: In apps/webapp/app/services/runsRepository.server.ts, the in-memory status filtering after fetching runs from Prisma is intentionally used as a workaround for ClickHouse data delays. This approach is acceptable because the result set is limited to a maximum of 100 runs due to pagination, making the performance impact negligible.

Applied to files:

  • packages/core/src/v3/schemas/api.ts
📚 Learning: 2026-03-02T12:42:56.114Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: apps/webapp/CLAUDE.md:0-0
Timestamp: 2026-03-02T12:42:56.114Z
Learning: Applies to apps/webapp/app/v3/services/**/*.server.ts : When editing services that branch on `RunEngineVersion` to support both V1 and V2 (e.g., `cancelTaskRun.server.ts`, `batchTriggerV3.server.ts`), only modify V2 code paths

Applied to files:

  • packages/core/src/v3/schemas/api.ts
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Use the `task()` function from `trigger.dev/sdk/v3` to define tasks with id and run properties

Applied to files:

  • packages/core/src/v3/schemas/api.ts
📚 Learning: 2026-03-13T13:37:49.544Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-13T13:37:49.544Z
Learning: Applies to **/*.{ts,tsx} : Use Run Engine 2.0 (internal/run-engine) and redis-worker for all new work - avoid DEPRECATED zodworker (Graphile-worker wrapper)

Applied to files:

  • packages/core/src/v3/schemas/api.ts
📚 Learning: 2026-03-02T12:42:56.114Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: apps/webapp/CLAUDE.md:0-0
Timestamp: 2026-03-02T12:42:56.114Z
Learning: Target Run Engine V2 for all new code; the `engineVersion.server.ts` file determines V1 vs V2 for a given environment

Applied to files:

  • packages/core/src/v3/schemas/api.ts
📚 Learning: 2025-11-27T16:26:58.661Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/webapp.mdc:0-0
Timestamp: 2025-11-27T16:26:58.661Z
Learning: Use the Run Engine 2.0 from `internal/run-engine` for new run lifecycle code in the webapp instead of the legacy run engine

Applied to files:

  • packages/core/src/v3/schemas/api.ts
📚 Learning: 2026-03-02T12:42:56.114Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: apps/webapp/CLAUDE.md:0-0
Timestamp: 2026-03-02T12:42:56.114Z
Learning: V1-only legacy code is located in `app/v3/marqs/`, `app/v3/legacyRunEngineWorker.server.ts`, `app/v3/services/triggerTaskV1.server.ts`, `app/v3/services/cancelTaskRunV1.server.ts`, `app/v3/authenticatedSocketConnection.server.ts`, and `app/v3/sharedSocketConnection.ts`

Applied to files:

  • packages/core/src/v3/schemas/api.ts
📚 Learning: 2026-03-02T12:42:56.114Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: apps/webapp/CLAUDE.md:0-0
Timestamp: 2026-03-02T12:42:56.114Z
Learning: All run lifecycle operations (triggering, completing, cancelling, etc.) should be performed through the singleton run engine instance in `app/v3/runEngine.server.ts` via service calls

Applied to files:

  • packages/core/src/v3/schemas/api.ts
📚 Learning: 2026-03-02T12:43:17.177Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: internal-packages/database/CLAUDE.md:0-0
Timestamp: 2026-03-02T12:43:17.177Z
Learning: New code should always target Prisma RunEngineVersion V2 (run-engine + redis-worker), not V1 (legacy MarQS + Graphile)

Applied to files:

  • packages/core/src/v3/schemas/api.ts
📚 Learning: 2026-03-02T12:42:56.114Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: apps/webapp/CLAUDE.md:0-0
Timestamp: 2026-03-02T12:42:56.114Z
Learning: Applies to apps/webapp/app/v3/*Worker.server.ts : New background job workers should use `trigger.dev/redis-worker` (e.g., `commonWorker.server.ts`, `alertsWorker.server.ts`, `batchTriggerWorker.server.ts`), not zodworker or graphile-worker

Applied to files:

  • packages/core/src/v3/schemas/api.ts
📚 Learning: 2025-11-27T16:26:37.432Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-27T16:26:37.432Z
Learning: Applies to {packages/core,apps/webapp}/**/*.{ts,tsx} : Use zod for validation in packages/core and apps/webapp

Applied to files:

  • packages/core/src/v3/schemas/api.ts
🔇 Additional comments (2)
packages/core/src/v3/schemas/api-type.test.ts (1)

143-269: Good schema test coverage for the new RunEvent contract.

These tests exercise success/failure paths, nullish handling, coercion behavior, and wrapped response parsing well.

packages/core/src/v3/schemas/api.ts (1)

1688-1692: List response wrapper schema is clean and explicit.

Using a dedicated { events: RunEvent[] } schema here is a solid upgrade over generic parsing.

Comment on lines +1646 to +1666
export const NanosecondTimestampSchema = z
.union([z.string(), z.number(), z.bigint()])
.transform((val) => {
// If it's already a Date, return it (though union doesn't include it)
if (typeof val === "object" && val instanceof Date) return val;

const str = val.toString();

// 19 digits is nanoseconds (e.g., 1710374400000000000)
if (str.length === 19) {
return new Date(Number(BigInt(str) / 1000000n));
}

// 13 digits is milliseconds
if (str.length === 13) {
return new Date(Number(val));
}

// Default to standard date coercion
return new Date(val as any);
});
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

In Zod v3, does .transform()automatically validate that a returnedDateis valid, and will a transform onz.union([z.string(), z.number(), z.bigint()])run when the input is aDate object?

💡 Result:

  • No. In Zod v3, .transform() runs after the input schema has parsed; Zod does not automatically re-validate the returned value (e.g., it won’t automatically reject an Invalid Date). If you need that, you must either add a check inside the transform via ctx (add an issue) or “pipe” into an output schema (e.g. a z.date() schema) to validate the post-transform value. [1], [2]

  • No. A .transform() attached to z.union([z.string(), z.number(), z.bigint()]) will only run if the union successfully parses the input. If the input is a Date object, none of those union branches match, so parsing fails and the transform is not executed. [3], [2]

Sources:
[1] Zod docs – Transforms API (z.transform, using ctx.issues for validation) https://zod.dev/api?id=preprocess
[2] Zod v3 README (npm) – ZodEffects runs transforms post-parsing https://www.npmjs.com/package/zod/v/3.0.0-alpha.19
[3] Zod docs – unions return the first option that validates successfully (i.e., must validate to proceed) https://zod.dev/?id=dates-1


Nanosecond timestamp transform does not validate returned Date and misses literal Date inputs.

In Zod v3, .transform() does not automatically validate its returned value, so invalid timestamps can produce Invalid Date objects that pass through. Additionally, the unreachable Date branch check is correct—since the union excludes z.date(), a literal Date input fails parsing before the transform runs.

🔧 Proposed fix
 export const NanosecondTimestampSchema = z
-  .union([z.string(), z.number(), z.bigint()])
+  .union([z.string(), z.number(), z.bigint(), z.date()])
   .transform((val) => {
-    // If it's already a Date, return it (though union doesn't include it)
-    if (typeof val === "object" && val instanceof Date) return val;
+    if (val instanceof Date) return val;
 
-    const str = val.toString();
+    const str = String(val);
 
-    // 19 digits is nanoseconds (e.g., 1710374400000000000)
-    if (str.length === 19) {
+    // 19 digits => nanoseconds
+    if (/^-?\d{19}$/.test(str)) {
       return new Date(Number(BigInt(str) / 1000000n));
     }
 
-    // 13 digits is milliseconds
-    if (str.length === 13) {
-      return new Date(Number(val));
+    // 13 digits => milliseconds
+    if (/^-?\d{13}$/.test(str)) {
+      return new Date(Number(str));
     }
 
-    // Default to standard date coercion
-    return new Date(val as any);
-  });
+    return new Date(str);
+  })
+  .pipe(z.date());
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const NanosecondTimestampSchema = z
.union([z.string(), z.number(), z.bigint()])
.transform((val) => {
// If it's already a Date, return it (though union doesn't include it)
if (typeof val === "object" && val instanceof Date) return val;
const str = val.toString();
// 19 digits is nanoseconds (e.g., 1710374400000000000)
if (str.length === 19) {
return new Date(Number(BigInt(str) / 1000000n));
}
// 13 digits is milliseconds
if (str.length === 13) {
return new Date(Number(val));
}
// Default to standard date coercion
return new Date(val as any);
});
export const NanosecondTimestampSchema = z
.union([z.string(), z.number(), z.bigint(), z.date()])
.transform((val) => {
if (val instanceof Date) return val;
const str = String(val);
// 19 digits => nanoseconds
if (/^-?\d{19}$/.test(str)) {
return new Date(Number(BigInt(str) / 1000000n));
}
// 13 digits => milliseconds
if (/^-?\d{13}$/.test(str)) {
return new Date(Number(str));
}
return new Date(str);
})
.pipe(z.date());
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/core/src/v3/schemas/api.ts` around lines 1646 - 1666,
NanosecondTimestampSchema's transform can return invalid Dates and never accepts
Date inputs; update the schema to include z.date() in the union so Date values
reach the transform (or handle them via a preprocess) and then validate the
transformed value by adding a refine that checks !isNaN(date.getTime()) with a
clear error message; reference NanosecondTimestampSchema and ensure the
transform still handles 19- and 13-digit strings but add the post-transform
validation (or replace transform with preprocess+parse and then z.date() to
guarantee a validated Date).

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