Skip to content

Conversation

@matt-aitken
Copy link
Member

@matt-aitken matt-aitken commented Jan 27, 2026

Summary

  • Query: add time limits, performance improvements, and styling updates

Changes

  • Add ClickHouse output_text and error_text columns with indexes
  • Automatically use _text columns for JSON based on query pattern; support JSON column data prefixes
  • Add idempotency key and scope columns
  • Add enforcedWhereClause for tenant and time restrictions, instead of the old tenant stuff.
  • Implement basic time filter limiting and set default time period based on plan; show message when results are clipped
  • UX: resizable code area (including vertical splits), collapsible sidebar, fix table/chart vertical sizing, max height for chart legend in fullscreen
  • Styling and UI tweaks: improved chart legend styling, more chart colours, thinner line chart stroke, pricing callout color, improved layout for callouts
  • Features: generate and save AI titles

Open with Devin

@changeset-bot
Copy link

changeset-bot bot commented Jan 27, 2026

⚠️ No Changeset found

Latest commit: 3c56314

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

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

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 27, 2026

Walkthrough

This diff introduces a household of coordinated changes: a new enforcedWhereClause model in the tsql package (types, PrinterContext, printer, tests) and renames WhereClauseFallback → WhereClauseCondition; ClickHouse client and executor now accept enforcedWhereClause and detect maxRows overflow; query execution API now returns ExecuteQueryResult with queryId and requires explicit organization/project/environment fields; adds AIQueryTitleService plus an ai-title route and DB migration adding CustomerQuery.title while removing costInCents; environment schema and several frontend components were updated (chart legend scrollable, AnimatedNumber decimals, table styling, Resizable UI, Callout visuals, chart tweaks), many route/UX changes for query title generation and time-filter maxPeriodDays, and multiple package/test adjustments.

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 34.62% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ❓ Inconclusive The description provides a comprehensive summary of changes organized by area (database, JSON handling, enforcement, UX, styling, features) with specific implementation details, but does not follow the provided template structure (missing Closes, Checklist, Testing, Changelog, Screenshots sections). Follow the repository's PR description template: include issue number with Closes #, complete the checklist, describe testing steps, provide changelog summary, and add screenshots if applicable.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title directly describes the main changes: adding time limits, implementing performance improvements, and applying styling updates to the query system.

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

✨ Finishing touches
  • 📝 Generate docstrings

📜 Recent review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 10eccd5 and 3c56314.

📒 Files selected for processing (2)
  • internal-packages/tsql/src/query/printer.test.ts
  • internal-packages/tsql/src/query/printer.ts
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{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}: Always import tasks from @trigger.dev/sdk, never use @trigger.dev/sdk/v3 or deprecated client.defineJob pattern
Every Trigger.dev task must be exported and have a unique id property with no timeouts in the run function

Files:

  • internal-packages/tsql/src/query/printer.ts
  • internal-packages/tsql/src/query/printer.test.ts
**/*.{ts,tsx,js,jsx}

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

Use function declarations instead of default exports

Import from @trigger.dev/core using subpaths only, never import from root

Files:

  • internal-packages/tsql/src/query/printer.ts
  • internal-packages/tsql/src/query/printer.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:

  • internal-packages/tsql/src/query/printer.ts
  • internal-packages/tsql/src/query/printer.test.ts
**/*.{js,ts,jsx,tsx,json,md,yaml,yml}

📄 CodeRabbit inference engine (AGENTS.md)

Format code using Prettier before committing

Files:

  • internal-packages/tsql/src/query/printer.ts
  • internal-packages/tsql/src/query/printer.test.ts
**/*.{test,spec}.{ts,tsx}

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

Use vitest for all tests in the Trigger.dev repository

Files:

  • internal-packages/tsql/src/query/printer.test.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

**/*.test.{ts,tsx,js,jsx}: Use vitest exclusively for testing and never mock anything - use testcontainers instead
Place test files next to source files with naming pattern: source file (e.g., MyService.ts) → MyService.test.ts

Files:

  • internal-packages/tsql/src/query/printer.test.ts
**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • internal-packages/tsql/src/query/printer.test.ts
🧬 Code graph analysis (1)
internal-packages/tsql/src/query/printer.test.ts (3)
internal-packages/tsql/src/index.ts (5)
  • createPrinterContext (119-119)
  • TableSchema (113-113)
  • column (81-81)
  • createSchemaRegistry (82-82)
  • PrinterContext (121-121)
internal-packages/tsql/src/query/printer_context.ts (2)
  • createPrinterContext (249-256)
  • PrinterContext (79-214)
internal-packages/tsql/src/query/schema.ts (3)
  • TableSchema (321-339)
  • column (354-366)
  • createSchemaRegistry (371-387)
⏰ 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). (12)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (2, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (7, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (7, 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 (4, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (6, 8)
  • GitHub Check: units / packages / 🧪 Unit Tests: Packages (1, 1)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (1, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (3, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (3, 8)
  • GitHub Check: typecheck / typecheck

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.


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.

Actionable comments posted: 12

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/webapp/app/components/runs/v3/SharedFilters.tsx (1)

529-540: Add missing dependencies to applySelection callback.
Line 529-540 references maxPeriodDays and exceedsMaxPeriod, but they’re missing from the dependency list, which can stale the validation/error message when props change.

🧩 Suggested fix
   }, [
     activeSection,
     selectedPeriod,
     isCustomDurationValid,
     customValue,
     customUnit,
     fromValue,
     toValue,
     replace,
     onApply,
     onValueChange,
+    maxPeriodDays,
+    exceedsMaxPeriod,
   ]);
🤖 Fix all issues with AI agents
In `@apps/webapp/app/components/code/TSQLResultsTable.tsx`:
- Line 1142: The tbody in TSQLResultsTable uses "divide-y divide-charcoal-700"
which doesn't show dividers for absolutely positioned/virtualized rows; remove
those utilities from the tbody className and instead add "border-b
border-charcoal-700" to the element that renders each virtualized row (the
per-row container/render function used by the virtualizer — e.g., the row
renderer / row element inside the map or renderRow handler) so each row gets its
own bottom border; update any row className/props (not the tbody) to include the
border utilities and remove the divide-y/divide-charcoal-700 from the tbody.

In `@apps/webapp/app/components/primitives/AnimatedNumber.tsx`:
- Around line 22-47: The decimals value used in the useTransform callback must
be clamped and sanitized before being passed to toLocaleString to avoid runtime
throws from invalid values; update the AnimatedNumber component to compute a
safeDecimals (based on decimalPlaces or getDecimalPlaces(value)) by coercing to
a finite number, rounding to an integer, and clamping into the 0–20 range (e.g.,
use Number.isFinite, Math.round, Math.max/Math.min) and then use safeDecimals
inside the display transformer and any branch that checks for zero; ensure NaN,
negatives, non-integers and >20 are handled by this normalization so
toLocaleString always receives a valid 0–20 integer.

In `@apps/webapp/app/components/runs/v3/SharedFilters.tsx`:
- Around line 441-452: The exceedsMaxPeriod calculation only checks fromValue
for date ranges and thus misses cases where only toValue is set; update the
date-range branch in exceedsMaxPeriod to compute the earliest selected date (min
of fromValue and toValue) and compare its age via dateRangeToDays (or convert
the computed range to days) against maxPeriodDays so "to-only" selections that
exceed maxPeriodDays also return true; locate the exceedsMaxPeriod IIFE and
adjust the date range logic that references activeSection, fromValue, toValue,
dateRangeToDays, and maxPeriodDays accordingly.

In
`@apps/webapp/app/routes/_app.orgs`.$organizationSlug.projects.$projectParam.env.$envParam.query/QueryHelpSidebar.tsx:
- Around line 70-76: The "guide" tab currently has double padding because
ClientTabsContent (value="guide") has className including "p-3" and its inner
div also has "p-3"; remove the outer padding to match the "ai" tab layout.
Locate the ClientTabsContent element with value="guide" and remove the "p-3"
from its className (leave the inner div wrapping TRQLGuideContent with its
"p-3"), ensuring visual alignment with the other tab; references:
ClientTabsContent and TRQLGuideContent.
- Around line 86-92: The "examples" tab duplicates padding because
ClientTabsContent has p-3 and the inner wrapper div also uses p-3; remove the
extra padding by deleting the p-3 on the inner div (the wrapper around
<ExamplesContent onTryExample={onTryExample} />) or adjust it to a neutral class
(e.g., remove padding or use p-0) so only ClientTabsContent provides the
padding; update the wrapper near ClientTabsContent/ExamplesContent to eliminate
the double padding.
- Around line 78-84: The "schema" tab shows double padding because both
ClientTabsContent (value="schema") and the inner div around TableSchemaContent
apply p-3; remove the redundant padding by deleting or changing the inner div's
padding class (the div wrapping TableSchemaContent) to p-0 (or remove p-3) so
only ClientTabsContent provides spacing; update the inner wrapper surrounding
TableSchemaContent to use no padding.

In
`@apps/webapp/app/routes/_app.orgs`.$organizationSlug.projects.$projectParam.env.$envParam.query/route.tsx:
- Around line 849-852: The className passed to ClientTabsContent contains a
typo: replace the incorrect "f-full" token with "h-full" so the height utility
is applied correctly; update the className string in the ClientTabsContent JSX
(the element with value="graph") to use "h-full" instead of "f-full".

In
`@apps/webapp/app/routes/resources.orgs`.$organizationSlug.projects.$projectParam.env.$envParam.query.ai-title.tsx:
- Around line 21-27: Wrap the call to request.json() in a try-catch so malformed
JSON returns a 400 instead of throwing; specifically, around the code that calls
request.json() before you call RequestSchema.safeParse, catch any error from
JSON parsing and return json({ success: false, error: "Invalid JSON", title:
null }, { status: 400 }); keep the existing RequestSchema.safeParse logic for
validated bodies and reference the same submission variable and response shape.
- Around line 59-65: The update lets any queryId be changed without verifying it
belongs to the current project/environment; restrict the update by either (A)
replacing prisma.customerQuery.update with prisma.customerQuery.updateMany({
where: { id: queryId, projectId: <currentProjectId>, environmentId:
<currentEnvId> }, data: { title } }) and verifying the returned count > 0, or
(B) first fetch the record with prisma.customerQuery.findUnique/findFirst({
where: { id: queryId } }), confirm its project/environment matches the current
project/env variables, then call prisma.customerQuery.update({ where: { id:
queryId }, data: { title } }); use the existing symbols queryId, title,
prisma.customerQuery.update/updateMany and the current project/env identifiers
in the file to implement this check.

In `@apps/webapp/app/services/queryService.server.ts`:
- Around line 104-112: The tenant inputs (organizationId, projectId,
environmentId) and enforcedWhereClause passed into executeQuery can diverge and
cause mismatched attribution for history/concurrency; update the executeQuery
parameter handling to validate and normalize tenant context by deriving the
enforcedWhereClause and history/concurrency keys from the canonical
organizationId/projectId/environmentId (or reject when inconsistent).
Specifically, in executeQuery (and the similar block around the other usage at
the 153-156 zone) check that any provided enforcedWhereClause matches the
computed clause for the given organizationId/projectId/environmentId (or rebuild
it from those IDs), and use the same canonical IDs to compute history and
customOrgConcurrencyLimit keys so all tenant guards are constructed from the
same source of truth.

In `@internal-packages/tsql/src/query/printer.ts`:
- Around line 2259-2267: The rootColumnSchema lookup currently calls
resolveFieldToColumnSchema([node.chain[0]]) which fails for qualified references
like ['runs','error',...]; change the input to include the table/alias when
present (e.g., use node.chain.length > 1 ? [node.chain[0], node.chain[1]] :
[node.chain[0]]) so resolveFieldToColumnSchema sees the table+column for JSON
columns; this ensures rootColumnSchema is correctly detected (so the .String
type hint is applied when this.queryHasGroupBy &&
!this.isInWhereComparisonContext()).
- Around line 1669-1733: createEnforcedGuard currently builds unqualified guard
expressions which can bind to the wrong table in multi-join queries; update
createConditionExpression to accept an optional tableAlias parameter and, when
provided, construct the Field.chain as [tableAlias, column] (instead of just
[column]) so resolveFieldChain will resolve to the correct table; then call
createConditionExpression(column, condition, tableAlias) from
createEnforcedGuard's loop and ensure existing logic in
createConditionExpression (used for between expressions and CompareOperation
building with createValueExpression and mapConditionOpToCompareOp) uses the new
fieldExpr with the qualified chain.
🧹 Nitpick comments (7)
apps/webapp/app/components/primitives/Callout.tsx (1)

8-14: Remove unused ChartBarIcon import.

The ChartBarIcon import at line 11 is not used anywhere in this file. It was likely replaced by CreditCardIcon in the pricing variant (line 65).

🧹 Proposed cleanup
 import {
   ArrowTopRightOnSquareIcon,
   BookOpenIcon,
-  ChartBarIcon,
   CheckCircleIcon,
   ChevronRightIcon,
 } from "@heroicons/react/24/solid";
apps/webapp/app/components/runs/v3/SharedFilters.tsx (1)

288-308: Prefer type aliases over interfaces for the TimeFilter types.
Line 288-308 uses interfaces, but the TS guideline prefers type aliases. Consider switching these to type for consistency.

♻️ Suggested refactor
-export interface TimeFilterApplyValues {
+export type TimeFilterApplyValues = {
   period?: string;
   from?: string;
   to?: string;
-}
+};

-export interface TimeFilterProps {
+export type TimeFilterProps = {
   defaultPeriod?: string;
   period?: string;
   from?: string;
   to?: string;
   /** Label name used in the filter display, defaults to "Created" */
   labelName?: string;
   hideLabel?: boolean;
   applyShortcut?: ShortcutDefinition | undefined;
   /** Callback when the user applies a time filter selection, receives the applied values */
   onValueChange?: (values: TimeFilterApplyValues) => void;
   /** When set an upgrade message will be shown if you select a period further back than this number of days */
   maxPeriodDays?: number;
-}
+};

As per coding guidelines, prefer types over interfaces.

apps/webapp/app/components/code/QueryResultsChart.tsx (1)

49-58: Prefer a type alias for QueryResultsChartProps.
This interface was modified; please switch it to a type to align with repo TS style.

♻️ Proposed change
-interface QueryResultsChartProps {
+type QueryResultsChartProps = {
   rows: Record<string, unknown>[];
   columns: OutputColumnMetadata[];
   config: ChartConfiguration;
   fullLegend?: boolean;
   /** Callback when "View all" legend button is clicked */
   onViewAllLegendItems?: () => void;
   /** When true, constrains legend to max 50% height with scrolling */
   legendScrollable?: boolean;
-}
+};

As per coding guidelines.

internal-packages/clickhouse/src/client/tsql.ts (1)

33-104: Prefer a type alias for ExecuteTSQLOptions.
This interface was modified; please switch it to a type to align with repo TS style.

♻️ Proposed change
-export interface ExecuteTSQLOptions<TOut extends z.ZodSchema> {
+export type ExecuteTSQLOptions<TOut extends z.ZodSchema> = {
   /** The name of the operation (for logging/tracing) */
   name: string;
   /** The TSQL query string to execute */
   query: string;
   /** The Zod schema for validating output rows */
   schema: TOut;
   /** Schema registry defining allowed tables and columns */
   tableSchema: TableSchema[];
   /**
    * REQUIRED: Conditions always applied at the table level.
    * Must include tenant columns (e.g., organization_id) for multi-tenant tables.
    * Applied to every table reference including subqueries, CTEs, and JOINs.
    *
    * `@example`
    * ```typescript
    * {
    *   // Tenant isolation
    *   organization_id: { op: "eq", value: "org_123" },
    *   project_id: { op: "eq", value: "proj_456" },
    *   environment_id: { op: "eq", value: "env_789" },
    *   // Plan-based time limit
    *   triggered_at: { op: "gte", value: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000) }
    * }
    * ```
    */
   enforcedWhereClause: Record<string, WhereClauseCondition | undefined>;
   /** Optional ClickHouse query settings */
   clickhouseSettings?: ClickHouseSettings;
   /** Optional TSQL query settings (maxRows, timezone, etc.) */
   querySettings?: Partial<QuerySettings>;
   /**
    * Whether to transform result values using the schema's valueMap
    * When enabled, internal ClickHouse values (e.g., 'COMPLETED_SUCCESSFULLY')
    * are converted to user-friendly display names (e.g., 'Completed')
    * `@default` true
    */
   transformValues?: boolean;
   /**
    * Runtime field mappings for dynamic value translation.
    * Maps internal ClickHouse values to external user-facing values.
    *
    * `@example`
    * ```typescript
    * {
    *   project: { "cm12345": "my-project-ref" },
    * }
    * ```
    */
   fieldMappings?: FieldMappings;
   /**
    * Run EXPLAIN instead of executing the query.
    * Returns the ClickHouse execution plan with index information.
    * Should only be used by admins for debugging query performance.
    * `@default` false
    */
   explain?: boolean;
   /**
    * Fallback WHERE conditions to apply when the user hasn't filtered on a column.
    * Key is the column name, value is the fallback condition.
    * These are applied at the AST level (top-level query only).
    *
    * `@example`
    * ```typescript
    * // Apply triggered_at >= 7 days ago if user doesn't filter on triggered_at
    * whereClauseFallback: {
    *   triggered_at: { op: 'gte', value: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000) }
    * }
    * ```
    */
   whereClauseFallback?: Record<string, WhereClauseCondition>;
-}
+};

As per coding guidelines.

internal-packages/tsql/src/query/printer_context.ts (1)

21-41: Prefer type aliases for new condition types.
Please switch these new interfaces to type aliases to align with the TS guideline. As per coding guidelines, use types over interfaces.

♻️ Proposed refactor
-export interface SimpleComparisonCondition {
+export type SimpleComparisonCondition = {
   /** The comparison operator */
   op: "eq" | "neq" | "gt" | "gte" | "lt" | "lte";
   /** The value to compare against */
   value: Date | string | number;
-}
+};

-export interface BetweenCondition {
+export type BetweenCondition = {
   /** The between operator */
   op: "between";
   /** The low bound of the range */
   low: Date | string | number;
   /** The high bound of the range */
   high: Date | string | number;
-}
+};
apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/route.tsx (2)

291-312: Non-null assertion relies on control flow that could be fragile.

The requestedFromDate! assertion at line 311 is safe in the current logic because when we reach the else branch, neither timeFilter.from nor timeFilter.to is set, so requestedFromDate was assigned at line 299. However, this relies on implicit coupling between the two code blocks.

Consider restructuring to make the invariant explicit, or add a defensive check:

♻️ Suggested improvement
   } else {
-    triggeredAtFallback = { op: "gte", value: requestedFromDate! };
+    // requestedFromDate is guaranteed non-null here because neither from nor to was specified,
+    // so we calculated it from the period at line 298-299
+    triggeredAtFallback = { op: "gte", value: requestedFromDate ?? new Date(Date.now() - 7 * 24 * 60 * 60 * 1000) };
   }

618-640: Title generation effect has a potential stale closure issue.

The effect depends on results but also reads from editorRef.current?.getQuery(). If the query in the editor changes between the effect trigger and the getQuery() call, the title generated won't match the results. While this is unlikely in practice due to React's batching, consider capturing the query at submission time instead.

Additionally, the dependency array includes organization.slug, project.slug, environment.slug which are used only to construct the action URL—these are unlikely to change during the component lifecycle, but including them is correct for completeness.

📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5fb9cc3 and 0806d27.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (33)
  • apps/webapp/app/components/code/QueryResultsChart.tsx
  • apps/webapp/app/components/code/TSQLResultsTable.tsx
  • apps/webapp/app/components/primitives/AnimatedNumber.tsx
  • apps/webapp/app/components/primitives/Callout.tsx
  • apps/webapp/app/components/primitives/Resizable.tsx
  • apps/webapp/app/components/primitives/charts/Card.tsx
  • apps/webapp/app/components/primitives/charts/ChartLegendCompound.tsx
  • apps/webapp/app/components/primitives/charts/ChartLine.tsx
  • apps/webapp/app/components/primitives/charts/ChartRoot.tsx
  • apps/webapp/app/components/runs/v3/SharedFilters.tsx
  • apps/webapp/app/env.server.ts
  • apps/webapp/app/presenters/v3/QueryPresenter.server.ts
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/QueryHelpSidebar.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/QueryHistoryPopover.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/route.tsx
  • apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query.ai-title.tsx
  • apps/webapp/app/services/queryService.server.ts
  • apps/webapp/app/v3/querySchemas.ts
  • apps/webapp/app/v3/services/aiQueryTitleService.server.ts
  • apps/webapp/package.json
  • internal-packages/clickhouse/schema/014_add_task_runs_v2_output_error_text.sql
  • internal-packages/clickhouse/schema/015_update_output_error_text_to_extract_data.sql
  • internal-packages/clickhouse/src/client/tsql.ts
  • internal-packages/clickhouse/src/index.ts
  • internal-packages/database/prisma/migrations/20260124203524_customer_query_add_title_remove_cost/migration.sql
  • internal-packages/database/prisma/schema.prisma
  • internal-packages/tsql/src/index.test.ts
  • internal-packages/tsql/src/index.ts
  • internal-packages/tsql/src/query/printer.test.ts
  • internal-packages/tsql/src/query/printer.ts
  • internal-packages/tsql/src/query/printer_context.ts
  • internal-packages/tsql/src/query/schema.ts
  • internal-packages/tsql/src/query/security.test.ts
💤 Files with no reviewable changes (1)
  • apps/webapp/app/env.server.ts
🧰 Additional context used
📓 Path-based instructions (14)
**/*.{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}: Always import tasks from @trigger.dev/sdk, never use @trigger.dev/sdk/v3 or deprecated client.defineJob pattern
Every Trigger.dev task must be exported and have a unique id property with no timeouts in the run function

Files:

  • apps/webapp/app/components/code/TSQLResultsTable.tsx
  • apps/webapp/app/presenters/v3/QueryPresenter.server.ts
  • apps/webapp/app/components/primitives/Callout.tsx
  • internal-packages/clickhouse/src/index.ts
  • internal-packages/tsql/src/query/schema.ts
  • apps/webapp/app/v3/services/aiQueryTitleService.server.ts
  • apps/webapp/app/components/primitives/charts/ChartLine.tsx
  • apps/webapp/app/components/primitives/Resizable.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/QueryHelpSidebar.tsx
  • apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query.ai-title.tsx
  • apps/webapp/app/components/primitives/charts/ChartRoot.tsx
  • apps/webapp/app/components/primitives/charts/Card.tsx
  • apps/webapp/app/components/primitives/AnimatedNumber.tsx
  • internal-packages/tsql/src/index.test.ts
  • internal-packages/tsql/src/query/security.test.ts
  • apps/webapp/app/v3/querySchemas.ts
  • apps/webapp/app/components/runs/v3/SharedFilters.tsx
  • internal-packages/clickhouse/src/client/tsql.ts
  • internal-packages/tsql/src/query/printer_context.ts
  • apps/webapp/app/components/code/QueryResultsChart.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/QueryHistoryPopover.tsx
  • apps/webapp/app/components/primitives/charts/ChartLegendCompound.tsx
  • internal-packages/tsql/src/query/printer.ts
  • internal-packages/tsql/src/query/printer.test.ts
  • internal-packages/tsql/src/index.ts
  • apps/webapp/app/services/queryService.server.ts
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/route.tsx
{packages/core,apps/webapp}/**/*.{ts,tsx}

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

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

Files:

  • apps/webapp/app/components/code/TSQLResultsTable.tsx
  • apps/webapp/app/presenters/v3/QueryPresenter.server.ts
  • apps/webapp/app/components/primitives/Callout.tsx
  • apps/webapp/app/v3/services/aiQueryTitleService.server.ts
  • apps/webapp/app/components/primitives/charts/ChartLine.tsx
  • apps/webapp/app/components/primitives/Resizable.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/QueryHelpSidebar.tsx
  • apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query.ai-title.tsx
  • apps/webapp/app/components/primitives/charts/ChartRoot.tsx
  • apps/webapp/app/components/primitives/charts/Card.tsx
  • apps/webapp/app/components/primitives/AnimatedNumber.tsx
  • apps/webapp/app/v3/querySchemas.ts
  • apps/webapp/app/components/runs/v3/SharedFilters.tsx
  • apps/webapp/app/components/code/QueryResultsChart.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/QueryHistoryPopover.tsx
  • apps/webapp/app/components/primitives/charts/ChartLegendCompound.tsx
  • apps/webapp/app/services/queryService.server.ts
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/route.tsx
**/*.{ts,tsx,js,jsx}

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

Use function declarations instead of default exports

Import from @trigger.dev/core using subpaths only, never import from root

Files:

  • apps/webapp/app/components/code/TSQLResultsTable.tsx
  • apps/webapp/app/presenters/v3/QueryPresenter.server.ts
  • apps/webapp/app/components/primitives/Callout.tsx
  • internal-packages/clickhouse/src/index.ts
  • internal-packages/tsql/src/query/schema.ts
  • apps/webapp/app/v3/services/aiQueryTitleService.server.ts
  • apps/webapp/app/components/primitives/charts/ChartLine.tsx
  • apps/webapp/app/components/primitives/Resizable.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/QueryHelpSidebar.tsx
  • apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query.ai-title.tsx
  • apps/webapp/app/components/primitives/charts/ChartRoot.tsx
  • apps/webapp/app/components/primitives/charts/Card.tsx
  • apps/webapp/app/components/primitives/AnimatedNumber.tsx
  • internal-packages/tsql/src/index.test.ts
  • internal-packages/tsql/src/query/security.test.ts
  • apps/webapp/app/v3/querySchemas.ts
  • apps/webapp/app/components/runs/v3/SharedFilters.tsx
  • internal-packages/clickhouse/src/client/tsql.ts
  • internal-packages/tsql/src/query/printer_context.ts
  • apps/webapp/app/components/code/QueryResultsChart.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/QueryHistoryPopover.tsx
  • apps/webapp/app/components/primitives/charts/ChartLegendCompound.tsx
  • internal-packages/tsql/src/query/printer.ts
  • internal-packages/tsql/src/query/printer.test.ts
  • internal-packages/tsql/src/index.ts
  • apps/webapp/app/services/queryService.server.ts
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/route.tsx
apps/webapp/app/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)

Access all environment variables through the env export of env.server.ts instead of directly accessing process.env in the Trigger.dev webapp

Files:

  • apps/webapp/app/components/code/TSQLResultsTable.tsx
  • apps/webapp/app/presenters/v3/QueryPresenter.server.ts
  • apps/webapp/app/components/primitives/Callout.tsx
  • apps/webapp/app/v3/services/aiQueryTitleService.server.ts
  • apps/webapp/app/components/primitives/charts/ChartLine.tsx
  • apps/webapp/app/components/primitives/Resizable.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/QueryHelpSidebar.tsx
  • apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query.ai-title.tsx
  • apps/webapp/app/components/primitives/charts/ChartRoot.tsx
  • apps/webapp/app/components/primitives/charts/Card.tsx
  • apps/webapp/app/components/primitives/AnimatedNumber.tsx
  • apps/webapp/app/v3/querySchemas.ts
  • apps/webapp/app/components/runs/v3/SharedFilters.tsx
  • apps/webapp/app/components/code/QueryResultsChart.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/QueryHistoryPopover.tsx
  • apps/webapp/app/components/primitives/charts/ChartLegendCompound.tsx
  • apps/webapp/app/services/queryService.server.ts
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/route.tsx
apps/webapp/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)

apps/webapp/**/*.{ts,tsx}: When importing from @trigger.dev/core in the webapp, use subpath exports from the package.json instead of importing from the root path
Follow the Remix 2.1.0 and Express server conventions when updating the main trigger.dev webapp

Access environment variables via env export from apps/webapp/app/env.server.ts, never use process.env directly

Files:

  • apps/webapp/app/components/code/TSQLResultsTable.tsx
  • apps/webapp/app/presenters/v3/QueryPresenter.server.ts
  • apps/webapp/app/components/primitives/Callout.tsx
  • apps/webapp/app/v3/services/aiQueryTitleService.server.ts
  • apps/webapp/app/components/primitives/charts/ChartLine.tsx
  • apps/webapp/app/components/primitives/Resizable.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/QueryHelpSidebar.tsx
  • apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query.ai-title.tsx
  • apps/webapp/app/components/primitives/charts/ChartRoot.tsx
  • apps/webapp/app/components/primitives/charts/Card.tsx
  • apps/webapp/app/components/primitives/AnimatedNumber.tsx
  • apps/webapp/app/v3/querySchemas.ts
  • apps/webapp/app/components/runs/v3/SharedFilters.tsx
  • apps/webapp/app/components/code/QueryResultsChart.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/QueryHistoryPopover.tsx
  • apps/webapp/app/components/primitives/charts/ChartLegendCompound.tsx
  • apps/webapp/app/services/queryService.server.ts
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/route.tsx
**/*.{js,ts,jsx,tsx,json,md,yaml,yml}

📄 CodeRabbit inference engine (AGENTS.md)

Format code using Prettier before committing

Files:

  • apps/webapp/app/components/code/TSQLResultsTable.tsx
  • apps/webapp/app/presenters/v3/QueryPresenter.server.ts
  • apps/webapp/package.json
  • apps/webapp/app/components/primitives/Callout.tsx
  • internal-packages/clickhouse/src/index.ts
  • internal-packages/tsql/src/query/schema.ts
  • apps/webapp/app/v3/services/aiQueryTitleService.server.ts
  • apps/webapp/app/components/primitives/charts/ChartLine.tsx
  • apps/webapp/app/components/primitives/Resizable.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/QueryHelpSidebar.tsx
  • apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query.ai-title.tsx
  • apps/webapp/app/components/primitives/charts/ChartRoot.tsx
  • apps/webapp/app/components/primitives/charts/Card.tsx
  • apps/webapp/app/components/primitives/AnimatedNumber.tsx
  • internal-packages/tsql/src/index.test.ts
  • internal-packages/tsql/src/query/security.test.ts
  • apps/webapp/app/v3/querySchemas.ts
  • apps/webapp/app/components/runs/v3/SharedFilters.tsx
  • internal-packages/clickhouse/src/client/tsql.ts
  • internal-packages/tsql/src/query/printer_context.ts
  • apps/webapp/app/components/code/QueryResultsChart.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/QueryHistoryPopover.tsx
  • apps/webapp/app/components/primitives/charts/ChartLegendCompound.tsx
  • internal-packages/tsql/src/query/printer.ts
  • internal-packages/tsql/src/query/printer.test.ts
  • internal-packages/tsql/src/index.ts
  • apps/webapp/app/services/queryService.server.ts
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/route.tsx
internal-packages/database/prisma/migrations/**/*.sql

📄 CodeRabbit inference engine (CLAUDE.md)

internal-packages/database/prisma/migrations/**/*.sql: When editing the Prisma schema, remove extraneous migration lines related to specific tables: _BackgroundWorkerToBackgroundWorkerFile, _BackgroundWorkerToTaskQueue, _TaskRunToTaskRunTag, _WaitpointRunConnections, _completedWaitpoints, SecretStore_key_idx, and unrelated TaskRun indexes
Database indexes must use CONCURRENTLY to avoid table locks and must be in their own separate migration file

Files:

  • internal-packages/database/prisma/migrations/20260124203524_customer_query_add_title_remove_cost/migration.sql
**/*.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:

  • apps/webapp/app/presenters/v3/QueryPresenter.server.ts
  • internal-packages/clickhouse/src/index.ts
  • internal-packages/tsql/src/query/schema.ts
  • apps/webapp/app/v3/services/aiQueryTitleService.server.ts
  • internal-packages/tsql/src/index.test.ts
  • internal-packages/tsql/src/query/security.test.ts
  • apps/webapp/app/v3/querySchemas.ts
  • internal-packages/clickhouse/src/client/tsql.ts
  • internal-packages/tsql/src/query/printer_context.ts
  • internal-packages/tsql/src/query/printer.ts
  • internal-packages/tsql/src/query/printer.test.ts
  • internal-packages/tsql/src/index.ts
  • apps/webapp/app/services/queryService.server.ts
internal-packages/clickhouse/schema/**/*.sql

📄 CodeRabbit inference engine (CLAUDE.md)

internal-packages/clickhouse/schema/**/*.sql: ClickHouse migrations must use Goose format with -- +goose Up and -- +goose Down markers
Follow ClickHouse naming conventions: raw_ prefix for input tables, _v1, _v2 suffixes for versioning, _mv_v1 suffix for materialized views

Files:

  • internal-packages/clickhouse/schema/014_add_task_runs_v2_output_error_text.sql
  • internal-packages/clickhouse/schema/015_update_output_error_text_to_extract_data.sql
apps/webapp/app/v3/services/**/*.server.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)

Organize services in the webapp following the pattern app/v3/services/*/*.server.ts

Files:

  • apps/webapp/app/v3/services/aiQueryTitleService.server.ts
**/*.{test,spec}.{ts,tsx}

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

Use vitest for all tests in the Trigger.dev repository

Files:

  • internal-packages/tsql/src/index.test.ts
  • internal-packages/tsql/src/query/security.test.ts
  • internal-packages/tsql/src/query/printer.test.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

**/*.test.{ts,tsx,js,jsx}: Use vitest exclusively for testing and never mock anything - use testcontainers instead
Place test files next to source files with naming pattern: source file (e.g., MyService.ts) → MyService.test.ts

Files:

  • internal-packages/tsql/src/index.test.ts
  • internal-packages/tsql/src/query/security.test.ts
  • internal-packages/tsql/src/query/printer.test.ts
**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • internal-packages/tsql/src/index.test.ts
  • internal-packages/tsql/src/query/security.test.ts
  • internal-packages/tsql/src/query/printer.test.ts
apps/webapp/app/services/**/*.server.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)

Separate testable services from configuration files; follow the pattern of realtimeClient.server.ts (testable service) and realtimeClientGlobal.server.ts (configuration) in the webapp

Files:

  • apps/webapp/app/services/queryService.server.ts
🧠 Learnings (24)
📚 Learning: 2026-01-15T11:50:06.067Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-15T11:50:06.067Z
Learning: Applies to internal-packages/database/prisma/migrations/**/*.sql : When editing the Prisma schema, remove extraneous migration lines related to specific tables: `_BackgroundWorkerToBackgroundWorkerFile`, `_BackgroundWorkerToTaskQueue`, `_TaskRunToTaskRunTag`, `_WaitpointRunConnections`, `_completedWaitpoints`, `SecretStore_key_idx`, and unrelated `TaskRun` indexes

Applied to files:

  • internal-packages/database/prisma/migrations/20260124203524_customer_query_add_title_remove_cost/migration.sql
  • internal-packages/clickhouse/schema/014_add_task_runs_v2_output_error_text.sql
  • internal-packages/clickhouse/schema/015_update_output_error_text_to_extract_data.sql
  • internal-packages/database/prisma/schema.prisma
📚 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: Applies to apps/webapp/**/*.{ts,tsx} : Follow the Remix 2.1.0 and Express server conventions when updating the main trigger.dev webapp

Applied to files:

  • apps/webapp/package.json
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/QueryHelpSidebar.tsx
  • apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query.ai-title.tsx
📚 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: Applies to apps/webapp/**/*.{ts,tsx} : When importing from `trigger.dev/core` in the webapp, use subpath exports from the package.json instead of importing from the root path

Applied to files:

  • apps/webapp/package.json
📚 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: The webapp at apps/webapp is a Remix 2.1 application using Node.js v20

Applied to files:

  • apps/webapp/package.json
📚 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: Applies to apps/webapp/app/**/*.{ts,tsx} : Access all environment variables through the `env` export of `env.server.ts` instead of directly accessing `process.env` in the Trigger.dev webapp

Applied to files:

  • apps/webapp/package.json
📚 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/trigger-sdk/**/*.{ts,tsx} : In the Trigger.dev SDK (packages/trigger-sdk), prefer isomorphic code like fetch and ReadableStream instead of Node.js-specific code

Applied to files:

  • apps/webapp/package.json
📚 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:

  • apps/webapp/package.json
📚 Learning: 2026-01-15T11:50:06.067Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-15T11:50:06.067Z
Learning: Applies to **/*.{ts,tsx} : Always import tasks from `trigger.dev/sdk`, never use `trigger.dev/sdk/v3` or deprecated `client.defineJob` pattern

Applied to files:

  • apps/webapp/package.json
📚 Learning: 2026-01-15T11:50:06.067Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-15T11:50:06.067Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Import from `trigger.dev/core` using subpaths only, never import from root

Applied to files:

  • apps/webapp/package.json
📚 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:

  • apps/webapp/package.json
📚 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 : Use build extensions in trigger.config.ts (additionalFiles, additionalPackages, aptGet, prismaExtension, etc.) to customize the build

Applied to files:

  • apps/webapp/package.json
📚 Learning: 2026-01-15T11:50:06.067Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-15T11:50:06.067Z
Learning: Applies to **/*.{ts,tsx} : Every Trigger.dev task must be exported and have a unique `id` property with no timeouts in the run function

Applied to files:

  • apps/webapp/package.json
📚 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:

  • apps/webapp/package.json
📚 Learning: 2025-10-08T11:48:12.327Z
Learnt from: nicktrn
Repo: triggerdotdev/trigger.dev PR: 2593
File: packages/core/src/v3/workers/warmStartClient.ts:168-170
Timestamp: 2025-10-08T11:48:12.327Z
Learning: The trigger.dev runners execute only in Node 21 and 22 environments, so modern Node.js APIs like AbortSignal.any (introduced in v20.3.0) are supported.

Applied to files:

  • apps/webapp/package.json
📚 Learning: 2026-01-15T11:50:06.067Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-15T11:50:06.067Z
Learning: Applies to internal-packages/clickhouse/schema/**/*.sql : Follow ClickHouse naming conventions: `raw_` prefix for input tables, `_v1`, `_v2` suffixes for versioning, `_mv_v1` suffix for materialized views

Applied to files:

  • internal-packages/clickhouse/schema/014_add_task_runs_v2_output_error_text.sql
  • internal-packages/clickhouse/schema/015_update_output_error_text_to_extract_data.sql
📚 Learning: 2026-01-15T11:50:06.067Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-15T11:50:06.067Z
Learning: Applies to internal-packages/clickhouse/schema/**/*.sql : ClickHouse migrations must use Goose format with `-- +goose Up` and `-- +goose Down` markers

Applied to files:

  • internal-packages/clickhouse/schema/014_add_task_runs_v2_output_error_text.sql
  • internal-packages/clickhouse/schema/015_update_output_error_text_to_extract_data.sql
📚 Learning: 2025-12-08T15:19:56.823Z
Learnt from: 0ski
Repo: triggerdotdev/trigger.dev PR: 2760
File: apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam/route.tsx:278-281
Timestamp: 2025-12-08T15:19:56.823Z
Learning: In apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam/route.tsx, the tableState search parameter uses intentional double-encoding: the parameter value contains a URL-encoded URLSearchParams string, so decodeURIComponent(value("tableState") ?? "") is required to fully decode it before parsing with new URLSearchParams(). This pattern allows bundling multiple filter/pagination params as a single search parameter.

Applied to files:

  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/QueryHelpSidebar.tsx
  • apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query.ai-title.tsx
  • internal-packages/tsql/src/query/security.test.ts
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/QueryHistoryPopover.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/route.tsx
📚 Learning: 2025-07-21T12:52:44.342Z
Learnt from: ericallam
Repo: triggerdotdev/trigger.dev PR: 2284
File: apps/webapp/app/services/realtimeClient.server.ts:111-127
Timestamp: 2025-07-21T12:52:44.342Z
Learning: Electric (the database service used in the realtimeClient) has built-in SQL injection protection and safely handles whereClause parameters passed via URL parameters, so direct string interpolation of runId values into SQL where clauses is safe when using Electric.

Applied to files:

  • internal-packages/tsql/src/query/security.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} : Scope idempotency keys globally or to current run using the scope parameter

Applied to files:

  • apps/webapp/app/v3/querySchemas.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 : Set default maximum duration in trigger.config.ts using `maxDuration` property

Applied to files:

  • apps/webapp/app/components/runs/v3/SharedFilters.tsx
📚 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} : Limit task duration using the `maxDuration` property (in seconds)

Applied to files:

  • apps/webapp/app/components/runs/v3/SharedFilters.tsx
📚 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:

  • internal-packages/clickhouse/src/client/tsql.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 internal-packages/database/**/*.{ts,tsx} : Use Prisma for database interactions in internal-packages/database with PostgreSQL

Applied to files:

  • apps/webapp/app/services/queryService.server.ts
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/route.tsx
📚 Learning: 2026-01-12T17:18:09.451Z
Learnt from: matt-aitken
Repo: triggerdotdev/trigger.dev PR: 2870
File: apps/webapp/app/services/redisConcurrencyLimiter.server.ts:56-66
Timestamp: 2026-01-12T17:18:09.451Z
Learning: In `apps/webapp/app/services/redisConcurrencyLimiter.server.ts`, the query concurrency limiter will not be deployed with Redis Cluster mode, so multi-key operations (keyKey and globalKey in different hash slots) are acceptable and will function correctly in standalone Redis mode.

Applied to files:

  • apps/webapp/app/services/queryService.server.ts
🧬 Code graph analysis (10)
apps/webapp/app/v3/services/aiQueryTitleService.server.ts (1)
apps/webapp/app/env.server.ts (1)
  • env (1320-1320)
apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/QueryHelpSidebar.tsx (6)
apps/webapp/app/components/primitives/ClientTabs.tsx (3)
  • ClientTabsList (211-211)
  • ClientTabsTrigger (211-211)
  • ClientTabsContent (211-211)
apps/webapp/app/assets/icons/AISparkleIcon.tsx (1)
  • AISparkleIcon (1-31)
apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/AITabContent.tsx (1)
  • AITabContent (6-65)
apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/TRQLGuideContent.tsx (1)
  • TRQLGuideContent (71-1203)
apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/TableSchemaContent.tsx (1)
  • TableSchemaContent (45-67)
apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/ExamplesContent.tsx (1)
  • ExamplesContent (60-81)
apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query.ai-title.tsx (6)
apps/webapp/app/utils/pathBuilder.ts (1)
  • EnvironmentParamSchema (26-28)
packages/core/src/v3/apps/http.ts (1)
  • json (65-75)
apps/webapp/app/models/project.server.ts (1)
  • findProjectBySlug (136-147)
apps/webapp/app/models/runtimeEnvironment.server.ts (1)
  • findEnvironmentBySlug (116-145)
apps/webapp/app/env.server.ts (1)
  • env (1320-1320)
apps/webapp/app/v3/services/aiQueryTitleService.server.ts (1)
  • AIQueryTitleService (15-71)
internal-packages/tsql/src/index.test.ts (2)
internal-packages/tsql/src/index.ts (2)
  • WhereClauseCondition (127-127)
  • compileTSQL (538-566)
internal-packages/tsql/src/query/printer_context.ts (1)
  • WhereClauseCondition (47-47)
apps/webapp/app/v3/querySchemas.ts (1)
internal-packages/tsql/src/query/schema.ts (1)
  • column (354-366)
apps/webapp/app/components/runs/v3/SharedFilters.tsx (3)
apps/webapp/app/components/primitives/Callout.tsx (1)
  • Callout (73-170)
apps/webapp/app/components/primitives/Buttons.tsx (1)
  • LinkButton (335-403)
apps/webapp/app/utils/pathBuilder.ts (1)
  • organizationBillingPath (116-118)
internal-packages/clickhouse/src/client/tsql.ts (3)
internal-packages/tsql/src/index.ts (1)
  • WhereClauseCondition (127-127)
internal-packages/clickhouse/src/index.ts (1)
  • WhereClauseCondition (59-59)
internal-packages/tsql/src/query/printer_context.ts (1)
  • WhereClauseCondition (47-47)
apps/webapp/app/components/primitives/charts/ChartLegendCompound.tsx (2)
apps/webapp/app/utils/cn.ts (1)
  • cn (77-79)
apps/webapp/app/components/primitives/AnimatedNumber.tsx (1)
  • AnimatedNumber (22-58)
internal-packages/tsql/src/index.ts (4)
internal-packages/tsql/src/query/printer_context.ts (3)
  • SimpleComparisonCondition (24-29)
  • WhereClauseCondition (47-47)
  • createPrinterContext (249-256)
internal-packages/clickhouse/src/client/tsql.ts (1)
  • WhereClauseCondition (28-28)
internal-packages/clickhouse/src/index.ts (1)
  • WhereClauseCondition (59-59)
internal-packages/tsql/src/query/schema.ts (1)
  • createSchemaRegistry (371-387)
apps/webapp/app/services/queryService.server.ts (3)
internal-packages/clickhouse/src/client/tsql.ts (1)
  • TSQLQueryResult (133-133)
apps/webapp/app/services/queryConcurrencyLimiter.server.ts (2)
  • queryConcurrencyLimiter (19-22)
  • GLOBAL_CONCURRENCY_LIMIT (28-28)
internal-packages/tsql/src/query/errors.ts (1)
  • QueryError (43-45)
⏰ 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). (20)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (1, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (1, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (2, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (4, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (8, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (5, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (6, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (3, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (8, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (7, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (7, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (2, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (6, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (4, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (3, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (5, 8)
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - npm)
  • GitHub Check: units / packages / 🧪 Unit Tests: Packages (1, 1)
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - pnpm)
  • GitHub Check: typecheck / typecheck

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

@matt-aitken matt-aitken force-pushed the query-output-error-idempotency branch 2 times, most recently from 9837a90 to 87ec51f Compare January 27, 2026 17:25
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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
apps/webapp/app/components/runs/v3/SharedFilters.tsx (1)

529-540: Missing maxPeriodDays in dependency array.

The applySelection callback references maxPeriodDays in the error message (line 459) but it's not included in the dependency array. While the current flow may work due to the disabled button preventing calls, this could cause stale values if the callback is invoked programmatically.

Suggested fix
   }, [
     activeSection,
     selectedPeriod,
     isCustomDurationValid,
     customValue,
     customUnit,
     fromValue,
     toValue,
     replace,
     onApply,
     onValueChange,
+    exceedsMaxPeriod,
+    maxPeriodDays,
   ]);
apps/webapp/app/v3/querySchemas.ts (1)

329-354: Add test coverage for NULL checks on JSON subfields with dataPrefix to verify the semantics are correct.

The implementation appears sound: dataPrefix injection and nullValue transformation work together correctly because the NULL comparison is applied after the field reference is visited (which injects the prefix). For example, WHERE output.message IS NULL with dataPrefix: "data" becomes equals(output.data.message, '{}') — correctly checking the wrapped field against empty object.

However, there is no explicit test covering this combined scenario. The test suite includes:

  • NULL checks on bare JSON columns with nullValue (lines 493–544)
  • NULL checks on bare JSON columns with textColumn (lines 800–812)
  • dataPrefix injection in SELECT/WHERE/GROUP BY (lines 901–1005)

But no test combines dataPrefix with NULL checks on subfields (e.g., WHERE output.message IS NULL or WHERE error.code IS NULL). Adding a test case would confirm the behavior is correct and prevent future regressions.

🤖 Fix all issues with AI agents
In `@internal-packages/tsql/src/query/printer_context.ts`:
- Around line 21-41: Replace the exported interfaces SimpleComparisonCondition
and BetweenCondition with exported type aliases that preserve the exact same
object shapes and string literal unions (e.g., export type
SimpleComparisonCondition = { op: "eq" | "neq" | "gt" | "gte" | "lt" | "lte";
value: Date | string | number; } and export type BetweenCondition = { op:
"between"; low: Date | string | number; high: Date | string | number; }); keep
JSDoc comments and exports intact so all callers using SimpleComparisonCondition
and BetweenCondition continue to compile.
🧹 Nitpick comments (4)
internal-packages/clickhouse/schema/014_update_output_error_text_to_extract_data.sql (2)

6-15: Consider the repeated toJSONString(output) calls.

The expression calls toJSONString(output) up to 3 times per row (lines 8, 11, and 12 or 13). Since this is a MATERIALIZED column computed at insert time rather than query time, the impact is limited to write performance. However, ClickHouse may not optimize away these redundant calls.

Unfortunately, ClickHouse's MATERIALIZED column syntax doesn't support CTEs or variable bindings within the expression, so there's no clean way to compute it once. If write performance becomes a concern, an alternative approach would be using a separate materialized view, but that adds complexity.

This is acceptable as-is given the tradeoff favors read performance.


2-2: Minor: Comment says "Update" but the action is "ADD COLUMN".

The comment "Update the materialized columns" suggests modifying existing columns, but the migration actually adds new columns. Consider clarifying this if it's intentional (e.g., replacing a previous approach).

-- +goose Up
--- Update the materialized columns to extract the 'data' field if it exists
+-- Add materialized text columns that extract the 'data' field if it exists
 -- This avoids the {"data": ...} wrapper in the text representation
apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/route.tsx (2)

618-640: Consider using titleFetcher.state in the dependency array.

The effect depends on titleFetcher object, but only checks titleFetcher.state in the condition. Including the entire fetcher object may trigger unnecessary effect runs since the fetcher reference can change between renders. Using titleFetcher.state would be more precise.

♻️ Suggested refinement
-  }, [results, shouldGenerateTitle, historyTitle, titleFetcher, organization.slug, project.slug, environment.slug]);
+  }, [results, shouldGenerateTitle, historyTitle, titleFetcher.state, organization.slug, project.slug, environment.slug]);

1086-1090: Minor inconsistency: DialogHeader doesn't show loading state.

The main chart header (line 1068) displays a loading spinner during title generation, but the DialogHeader (line 1089) falls back to "Chart" directly. If the dialog is opened while the title is still generating, users see inconsistent UI.

♻️ Suggested fix for consistency
           <DialogHeader>
-            {queryTitle ?? "Chart"}
+            {titleContent}
           </DialogHeader>
📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0806d27 and 9837a90.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (32)
  • apps/webapp/app/components/code/QueryResultsChart.tsx
  • apps/webapp/app/components/code/TSQLResultsTable.tsx
  • apps/webapp/app/components/primitives/AnimatedNumber.tsx
  • apps/webapp/app/components/primitives/Callout.tsx
  • apps/webapp/app/components/primitives/Resizable.tsx
  • apps/webapp/app/components/primitives/charts/Card.tsx
  • apps/webapp/app/components/primitives/charts/ChartLegendCompound.tsx
  • apps/webapp/app/components/primitives/charts/ChartLine.tsx
  • apps/webapp/app/components/primitives/charts/ChartRoot.tsx
  • apps/webapp/app/components/runs/v3/SharedFilters.tsx
  • apps/webapp/app/env.server.ts
  • apps/webapp/app/presenters/v3/QueryPresenter.server.ts
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/QueryHelpSidebar.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/QueryHistoryPopover.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/route.tsx
  • apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query.ai-title.tsx
  • apps/webapp/app/services/queryService.server.ts
  • apps/webapp/app/v3/querySchemas.ts
  • apps/webapp/app/v3/services/aiQueryTitleService.server.ts
  • apps/webapp/package.json
  • internal-packages/clickhouse/schema/014_update_output_error_text_to_extract_data.sql
  • internal-packages/clickhouse/src/client/tsql.ts
  • internal-packages/clickhouse/src/index.ts
  • internal-packages/database/prisma/migrations/20260124203524_customer_query_add_title_remove_cost/migration.sql
  • internal-packages/database/prisma/schema.prisma
  • internal-packages/tsql/src/index.test.ts
  • internal-packages/tsql/src/index.ts
  • internal-packages/tsql/src/query/printer.test.ts
  • internal-packages/tsql/src/query/printer.ts
  • internal-packages/tsql/src/query/printer_context.ts
  • internal-packages/tsql/src/query/schema.ts
  • internal-packages/tsql/src/query/security.test.ts
💤 Files with no reviewable changes (1)
  • apps/webapp/app/env.server.ts
🚧 Files skipped from review as they are similar to previous changes (16)
  • internal-packages/tsql/src/query/schema.ts
  • internal-packages/clickhouse/src/index.ts
  • internal-packages/database/prisma/migrations/20260124203524_customer_query_add_title_remove_cost/migration.sql
  • apps/webapp/app/components/primitives/AnimatedNumber.tsx
  • apps/webapp/app/components/code/QueryResultsChart.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/QueryHelpSidebar.tsx
  • apps/webapp/app/components/primitives/charts/ChartLine.tsx
  • apps/webapp/app/components/code/TSQLResultsTable.tsx
  • apps/webapp/app/v3/services/aiQueryTitleService.server.ts
  • apps/webapp/app/components/primitives/charts/Card.tsx
  • apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query.ai-title.tsx
  • internal-packages/database/prisma/schema.prisma
  • apps/webapp/package.json
  • apps/webapp/app/presenters/v3/QueryPresenter.server.ts
  • internal-packages/clickhouse/src/client/tsql.ts
  • apps/webapp/app/components/primitives/Callout.tsx
🧰 Additional context used
📓 Path-based instructions (12)
internal-packages/clickhouse/schema/**/*.sql

📄 CodeRabbit inference engine (CLAUDE.md)

internal-packages/clickhouse/schema/**/*.sql: ClickHouse migrations must use Goose format with -- +goose Up and -- +goose Down markers
Follow ClickHouse naming conventions: raw_ prefix for input tables, _v1, _v2 suffixes for versioning, _mv_v1 suffix for materialized views

Files:

  • internal-packages/clickhouse/schema/014_update_output_error_text_to_extract_data.sql
**/*.{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}: Always import tasks from @trigger.dev/sdk, never use @trigger.dev/sdk/v3 or deprecated client.defineJob pattern
Every Trigger.dev task must be exported and have a unique id property with no timeouts in the run function

Files:

  • apps/webapp/app/components/primitives/charts/ChartRoot.tsx
  • apps/webapp/app/components/runs/v3/SharedFilters.tsx
  • internal-packages/tsql/src/query/printer.ts
  • internal-packages/tsql/src/index.test.ts
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/QueryHistoryPopover.tsx
  • internal-packages/tsql/src/query/printer_context.ts
  • internal-packages/tsql/src/query/security.test.ts
  • apps/webapp/app/components/primitives/charts/ChartLegendCompound.tsx
  • internal-packages/tsql/src/query/printer.test.ts
  • apps/webapp/app/components/primitives/Resizable.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/route.tsx
  • internal-packages/tsql/src/index.ts
  • apps/webapp/app/v3/querySchemas.ts
  • apps/webapp/app/services/queryService.server.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:

  • apps/webapp/app/components/primitives/charts/ChartRoot.tsx
  • apps/webapp/app/components/runs/v3/SharedFilters.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/QueryHistoryPopover.tsx
  • apps/webapp/app/components/primitives/charts/ChartLegendCompound.tsx
  • apps/webapp/app/components/primitives/Resizable.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/route.tsx
  • apps/webapp/app/v3/querySchemas.ts
  • apps/webapp/app/services/queryService.server.ts
**/*.{ts,tsx,js,jsx}

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

Use function declarations instead of default exports

Import from @trigger.dev/core using subpaths only, never import from root

Files:

  • apps/webapp/app/components/primitives/charts/ChartRoot.tsx
  • apps/webapp/app/components/runs/v3/SharedFilters.tsx
  • internal-packages/tsql/src/query/printer.ts
  • internal-packages/tsql/src/index.test.ts
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/QueryHistoryPopover.tsx
  • internal-packages/tsql/src/query/printer_context.ts
  • internal-packages/tsql/src/query/security.test.ts
  • apps/webapp/app/components/primitives/charts/ChartLegendCompound.tsx
  • internal-packages/tsql/src/query/printer.test.ts
  • apps/webapp/app/components/primitives/Resizable.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/route.tsx
  • internal-packages/tsql/src/index.ts
  • apps/webapp/app/v3/querySchemas.ts
  • apps/webapp/app/services/queryService.server.ts
apps/webapp/app/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)

Access all environment variables through the env export of env.server.ts instead of directly accessing process.env in the Trigger.dev webapp

Files:

  • apps/webapp/app/components/primitives/charts/ChartRoot.tsx
  • apps/webapp/app/components/runs/v3/SharedFilters.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/QueryHistoryPopover.tsx
  • apps/webapp/app/components/primitives/charts/ChartLegendCompound.tsx
  • apps/webapp/app/components/primitives/Resizable.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/route.tsx
  • apps/webapp/app/v3/querySchemas.ts
  • apps/webapp/app/services/queryService.server.ts
apps/webapp/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)

apps/webapp/**/*.{ts,tsx}: When importing from @trigger.dev/core in the webapp, use subpath exports from the package.json instead of importing from the root path
Follow the Remix 2.1.0 and Express server conventions when updating the main trigger.dev webapp

Access environment variables via env export from apps/webapp/app/env.server.ts, never use process.env directly

Files:

  • apps/webapp/app/components/primitives/charts/ChartRoot.tsx
  • apps/webapp/app/components/runs/v3/SharedFilters.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/QueryHistoryPopover.tsx
  • apps/webapp/app/components/primitives/charts/ChartLegendCompound.tsx
  • apps/webapp/app/components/primitives/Resizable.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/route.tsx
  • apps/webapp/app/v3/querySchemas.ts
  • apps/webapp/app/services/queryService.server.ts
**/*.{js,ts,jsx,tsx,json,md,yaml,yml}

📄 CodeRabbit inference engine (AGENTS.md)

Format code using Prettier before committing

Files:

  • apps/webapp/app/components/primitives/charts/ChartRoot.tsx
  • apps/webapp/app/components/runs/v3/SharedFilters.tsx
  • internal-packages/tsql/src/query/printer.ts
  • internal-packages/tsql/src/index.test.ts
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/QueryHistoryPopover.tsx
  • internal-packages/tsql/src/query/printer_context.ts
  • internal-packages/tsql/src/query/security.test.ts
  • apps/webapp/app/components/primitives/charts/ChartLegendCompound.tsx
  • internal-packages/tsql/src/query/printer.test.ts
  • apps/webapp/app/components/primitives/Resizable.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/route.tsx
  • internal-packages/tsql/src/index.ts
  • apps/webapp/app/v3/querySchemas.ts
  • apps/webapp/app/services/queryService.server.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:

  • internal-packages/tsql/src/query/printer.ts
  • internal-packages/tsql/src/index.test.ts
  • internal-packages/tsql/src/query/printer_context.ts
  • internal-packages/tsql/src/query/security.test.ts
  • internal-packages/tsql/src/query/printer.test.ts
  • internal-packages/tsql/src/index.ts
  • apps/webapp/app/v3/querySchemas.ts
  • apps/webapp/app/services/queryService.server.ts
**/*.{test,spec}.{ts,tsx}

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

Use vitest for all tests in the Trigger.dev repository

Files:

  • internal-packages/tsql/src/index.test.ts
  • internal-packages/tsql/src/query/security.test.ts
  • internal-packages/tsql/src/query/printer.test.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

**/*.test.{ts,tsx,js,jsx}: Use vitest exclusively for testing and never mock anything - use testcontainers instead
Place test files next to source files with naming pattern: source file (e.g., MyService.ts) → MyService.test.ts

Files:

  • internal-packages/tsql/src/index.test.ts
  • internal-packages/tsql/src/query/security.test.ts
  • internal-packages/tsql/src/query/printer.test.ts
**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • internal-packages/tsql/src/index.test.ts
  • internal-packages/tsql/src/query/security.test.ts
  • internal-packages/tsql/src/query/printer.test.ts
apps/webapp/app/services/**/*.server.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)

Separate testable services from configuration files; follow the pattern of realtimeClient.server.ts (testable service) and realtimeClientGlobal.server.ts (configuration) in the webapp

Files:

  • apps/webapp/app/services/queryService.server.ts
🧠 Learnings (11)
📚 Learning: 2026-01-15T11:50:06.067Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-15T11:50:06.067Z
Learning: Applies to internal-packages/clickhouse/schema/**/*.sql : Follow ClickHouse naming conventions: `raw_` prefix for input tables, `_v1`, `_v2` suffixes for versioning, `_mv_v1` suffix for materialized views

Applied to files:

  • internal-packages/clickhouse/schema/014_update_output_error_text_to_extract_data.sql
📚 Learning: 2026-01-15T11:50:06.067Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-15T11:50:06.067Z
Learning: Applies to internal-packages/clickhouse/schema/**/*.sql : ClickHouse migrations must use Goose format with `-- +goose Up` and `-- +goose Down` markers

Applied to files:

  • internal-packages/clickhouse/schema/014_update_output_error_text_to_extract_data.sql
📚 Learning: 2026-01-15T11:50:06.067Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-15T11:50:06.067Z
Learning: Applies to internal-packages/database/prisma/migrations/**/*.sql : When editing the Prisma schema, remove extraneous migration lines related to specific tables: `_BackgroundWorkerToBackgroundWorkerFile`, `_BackgroundWorkerToTaskQueue`, `_TaskRunToTaskRunTag`, `_WaitpointRunConnections`, `_completedWaitpoints`, `SecretStore_key_idx`, and unrelated `TaskRun` indexes

Applied to files:

  • internal-packages/clickhouse/schema/014_update_output_error_text_to_extract_data.sql
📚 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 : Set default maximum duration in trigger.config.ts using `maxDuration` property

Applied to files:

  • apps/webapp/app/components/runs/v3/SharedFilters.tsx
📚 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} : Limit task duration using the `maxDuration` property (in seconds)

Applied to files:

  • apps/webapp/app/components/runs/v3/SharedFilters.tsx
📚 Learning: 2025-12-08T15:19:56.823Z
Learnt from: 0ski
Repo: triggerdotdev/trigger.dev PR: 2760
File: apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam/route.tsx:278-281
Timestamp: 2025-12-08T15:19:56.823Z
Learning: In apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam/route.tsx, the tableState search parameter uses intentional double-encoding: the parameter value contains a URL-encoded URLSearchParams string, so decodeURIComponent(value("tableState") ?? "") is required to fully decode it before parsing with new URLSearchParams(). This pattern allows bundling multiple filter/pagination params as a single search parameter.

Applied to files:

  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/QueryHistoryPopover.tsx
  • internal-packages/tsql/src/query/security.test.ts
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/route.tsx
📚 Learning: 2025-07-21T12:52:44.342Z
Learnt from: ericallam
Repo: triggerdotdev/trigger.dev PR: 2284
File: apps/webapp/app/services/realtimeClient.server.ts:111-127
Timestamp: 2025-07-21T12:52:44.342Z
Learning: Electric (the database service used in the realtimeClient) has built-in SQL injection protection and safely handles whereClause parameters passed via URL parameters, so direct string interpolation of runId values into SQL where clauses is safe when using Electric.

Applied to files:

  • internal-packages/tsql/src/query/security.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 internal-packages/database/**/*.{ts,tsx} : Use Prisma for database interactions in internal-packages/database with PostgreSQL

Applied to files:

  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/route.tsx
  • apps/webapp/app/services/queryService.server.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} : Scope idempotency keys globally or to current run using the scope parameter

Applied to files:

  • apps/webapp/app/v3/querySchemas.ts
📚 Learning: 2025-08-14T10:53:54.526Z
Learnt from: myftija
Repo: triggerdotdev/trigger.dev PR: 2391
File: apps/webapp/app/services/organizationAccessToken.server.ts:50-0
Timestamp: 2025-08-14T10:53:54.526Z
Learning: In the Trigger.dev codebase, token service functions (like revokePersonalAccessToken and revokeOrganizationAccessToken) don't include tenant scoping in their database queries. Instead, authorization and tenant scoping happens at a higher level in the authentication flow (typically in route handlers) before these service functions are called. This is a consistent pattern across both Personal Access Tokens (PATs) and Organization Access Tokens (OATs).

Applied to files:

  • apps/webapp/app/services/queryService.server.ts
📚 Learning: 2026-01-12T17:18:09.451Z
Learnt from: matt-aitken
Repo: triggerdotdev/trigger.dev PR: 2870
File: apps/webapp/app/services/redisConcurrencyLimiter.server.ts:56-66
Timestamp: 2026-01-12T17:18:09.451Z
Learning: In `apps/webapp/app/services/redisConcurrencyLimiter.server.ts`, the query concurrency limiter will not be deployed with Redis Cluster mode, so multi-key operations (keyKey and globalKey in different hash slots) are acceptable and will function correctly in standalone Redis mode.

Applied to files:

  • apps/webapp/app/services/queryService.server.ts
🧬 Code graph analysis (7)
apps/webapp/app/components/runs/v3/SharedFilters.tsx (3)
apps/webapp/app/components/primitives/Callout.tsx (1)
  • Callout (73-170)
apps/webapp/app/components/primitives/Buttons.tsx (1)
  • LinkButton (335-403)
apps/webapp/app/utils/pathBuilder.ts (1)
  • organizationBillingPath (116-118)
internal-packages/tsql/src/index.test.ts (5)
internal-packages/tsql/src/index.ts (4)
  • column (81-81)
  • TableSchema (113-113)
  • WhereClauseCondition (127-127)
  • compileTSQL (538-566)
apps/webapp/app/services/queryService.server.ts (1)
  • TableSchema (21-21)
internal-packages/clickhouse/src/client/tsql.ts (2)
  • TableSchema (28-28)
  • WhereClauseCondition (28-28)
internal-packages/clickhouse/src/index.ts (2)
  • TableSchema (54-54)
  • WhereClauseCondition (59-59)
internal-packages/tsql/src/query/printer_context.ts (1)
  • WhereClauseCondition (47-47)
internal-packages/tsql/src/query/printer_context.ts (2)
internal-packages/tsql/src/index.ts (8)
  • SimpleComparisonCondition (126-126)
  • BetweenCondition (122-122)
  • WhereClauseCondition (127-127)
  • SchemaRegistry (112-112)
  • FieldMappings (109-109)
  • createPrinterContext (119-119)
  • PrinterContextOptions (123-123)
  • PrinterContext (121-121)
internal-packages/tsql/src/query/schema.ts (2)
  • SchemaRegistry (344-349)
  • FieldMappings (270-270)
apps/webapp/app/components/primitives/charts/ChartLegendCompound.tsx (2)
apps/webapp/app/utils/cn.ts (1)
  • cn (77-79)
apps/webapp/app/components/primitives/AnimatedNumber.tsx (1)
  • AnimatedNumber (22-58)
internal-packages/tsql/src/query/printer.test.ts (1)
internal-packages/tsql/src/query/printer_context.ts (2)
  • createPrinterContext (249-256)
  • PrinterContext (79-214)
apps/webapp/app/v3/querySchemas.ts (1)
internal-packages/tsql/src/query/schema.ts (1)
  • column (354-366)
apps/webapp/app/services/queryService.server.ts (4)
internal-packages/clickhouse/src/client/tsql.ts (1)
  • TSQLQueryResult (133-133)
internal-packages/clickhouse/src/index.ts (2)
  • TSQLQueryResult (55-55)
  • QueryError (64-64)
apps/webapp/app/services/queryConcurrencyLimiter.server.ts (2)
  • queryConcurrencyLimiter (19-22)
  • GLOBAL_CONCURRENCY_LIMIT (28-28)
internal-packages/tsql/src/query/errors.ts (1)
  • QueryError (43-45)
⏰ 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). (22)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (2, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (2, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (7, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (7, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (3, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (6, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (8, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (5, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (4, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (5, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (1, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (6, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (8, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (4, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (1, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (3, 8)
  • GitHub Check: units / packages / 🧪 Unit Tests: Packages (1, 1)
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - npm)
  • GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - npm)
  • GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - pnpm)
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - pnpm)
  • GitHub Check: typecheck / typecheck
🔇 Additional comments (48)
apps/webapp/app/components/primitives/Resizable.tsx (3)

28-40: LGTM!

The orientation-aware styling using data-[handle-orientation=vertical] selectors is well-structured. The base horizontal styles with vertical overrides pattern is clean and maintainable.


44-47: LGTM!

The line indicators properly toggle visibility based on orientation using complementary hidden/block classes with the group-data-[handle-orientation=vertical] selector. The hover transitions are smooth and provide good visual feedback.


48-63: LGTM!

The orientation-aware dot rendering is well-implemented. Using index as the key is acceptable here since the array is static, fixed-length, and items never reorder. The visibility logic correctly shows only the relevant orientation's dots while hiding both on hover to reveal the line indicator.

internal-packages/clickhouse/schema/014_update_output_error_text_to_extract_data.sql (3)

1-5: Goose format and naming conventions are correct.

The migration properly uses -- +goose Up and -- +goose Down markers, and task_runs_v2 follows the versioning suffix convention. As per coding guidelines and learnings.


29-32: Index configuration looks appropriate for text search.

The ngrambf_v1(3, 131072, 3, 0) bloom filter with 3-character ngrams is well-suited for substring matching on JSON text fields.


34-45: Down migration is correctly structured.

Indexes are dropped before columns, and IF EXISTS guards protect against partial migration states. Good defensive practice.

apps/webapp/app/components/primitives/charts/ChartLegendCompound.tsx (2)

9-43: Scrollable prop is cleanly added and defaulted.
Good addition to the public API with a sensible default for backward compatibility.


134-216: Scrollable legend layout looks solid.
The max-height constraint, shrink-0 guards, and overflow wrapper are well composed for flex layouts.

apps/webapp/app/components/primitives/charts/ChartRoot.tsx (2)

9-105: Legend scrollability is wired through cleanly.
Defaults and prop forwarding are consistent across the root component.


109-170: Inner wiring to ChartLegendCompound is correct.
scrollable is passed through without side effects.

apps/webapp/app/components/runs/v3/SharedFilters.tsx (6)

14-29: LGTM!

The new imports are well-organized and all are utilized in the component for the upgrade callout feature.


126-140: LGTM!

The utility functions are well-implemented. periodToDays leverages the existing parse-duration library for consistency, and dateRangeToDays uses ceiling to ensure partial days count conservatively.


797-806: LGTM!

The upgrade callout is well-implemented with proper conditional rendering, pluralization via simplur, and correct routing to the billing page using organizationBillingPath.


738-762: LGTM!

The quick date button changes improve semantic correctness. Using endOfDay, endOfWeek, and endOfMonth for the "to" values ensures the selected ranges cover the full intended periods rather than stopping at the current timestamp.


823-838: LGTM!

Disabling the Apply button when exceedsMaxPeriod is true provides clear UX feedback and prevents invalid submissions.


93-109: LGTM!

Adding the "5 days" preset provides users with a useful intermediate option between 3 and 7 days.

apps/webapp/app/v3/querySchemas.ts (1)

170-178: No action needed. The idempotency scope values are correctly defined and match the backend support. All three scopes—"run", "attempt", and "global"—are officially supported throughout the codebase.

internal-packages/tsql/src/query/printer_context.ts (1)

95-199: LGTM: enforcedWhereClause is consistently propagated.

Also applies to: 219-255

internal-packages/tsql/src/index.ts (2)

26-32: LGTM: WhereClauseCondition wiring across helpers is consistent.

Also applies to: 118-128, 316-367, 377-444


450-504: LGTM: enforcedWhereClause sanitization + context creation look solid.

Also applies to: 542-565

internal-packages/tsql/src/query/security.test.ts (2)

55-61: LGTM: default test options migrated to enforcedWhereClause.


417-421: LGTM: optional tenant filter permutations updated for enforcedWhereClause.

Also applies to: 438-443, 459-463, 491-496, 516-520, 535-539, 559-563, 578-582

apps/webapp/app/services/queryService.server.ts (1)

57-87: LGTM: 3‑tuple result + queryId propagation look consistent.

Also applies to: 89-99, 121-134, 164-218

internal-packages/tsql/src/query/printer.test.ts (4)

88-94: LGTM: test contexts updated for enforcedWhereClause.

Also applies to: 155-164, 221-229, 248-258, 481-491, 697-707, 888-898, 1152-1157, 1469-1485, 1585-1604, 1811-1832, 2054-2074, 2201-2227, 2614-2645, 2769-2785, 2899-2921, 3084-3093


611-664: LGTM: JSON subfield type‑hint suppression in WHERE is covered.


666-855: LGTM: textColumn optimization scenarios are well covered.


857-1007: LGTM: dataPrefix injection behavior is well covered.

internal-packages/tsql/src/index.test.ts (3)

8-74: LGTM: scaffolding updated for enforcedWhereClause and new schemas.


168-243: LGTM: fallback tests updated to WhereClauseCondition.


516-828: LGTM: enforcedWhereClause behavior suite is comprehensive.

internal-packages/tsql/src/query/printer.ts (12)

117-118: LGTM!

Good addition of the queryHasGroupBy flag with clear documentation explaining its purpose for JSON subfield type hints in GROUP BY queries.


397-400: LGTM!

Proper state management pattern for queryHasGroupBy - saving before modification and restoring after subquery processing, consistent with the existing savedTableContexts approach.


639-678: LGTM!

Well-structured logic flow for handling different column types:

  1. Text column optimization for bare JSON fields
  2. Virtual column expression aliasing
  3. JSON subfield aliasing (excluding dataPrefix)
  4. ClickHouse name mismatch aliasing

The effectiveOutputName override ensures metadata consistency with the generated alias.


696-710: LGTM!

Correctly handles the case where a user explicitly aliases a JSON column with a textColumn optimization (e.g., SELECT output AS myOutput), using the optimized text column while preserving the user's explicit alias.


853-857: LGTM!

Consistent application of textColumn optimization during SELECT * expansion, with proper aliasing to preserve the user-facing column name.


1479-1480: LGTM!

Good fail-fast validation of required tenant columns early in join processing. This ensures tenant isolation requirements are enforced before query execution.


1590-1604: LGTM!

Proper tenant isolation validation - ensures the required organizationId column is present in enforcedWhereClause. The error message clearly identifies the missing requirement.


1606-1638: LGTM!

Correct date handling for ClickHouse:

  • Uses UTC methods consistently for timezone-safe formatting
  • toDateTime64(..., 3) matches DateTime64(3) column precision
  • Format string matches ClickHouse's expected format

1868-1881: LGTM!

Good optimization to use textColumn for string-based comparisons (Eq, NotEq, Like, ILike, etc.) where the text representation is more efficient. Correctly excludes numeric comparisons (Lt, Gt, etc.) where the text column wouldn't provide correct semantics.


2296-2308: LGTM!

Clean implementation of isInWhereComparisonContext() that correctly identifies WHERE/HAVING comparison contexts without including GROUP BY. This enables proper differentiation for JSON type hint handling.


2351-2419: LGTM!

Well-implemented helper methods for text column and data prefix detection:

  • getTextColumnForField correctly identifies bare JSON fields vs. subfield access
  • getDataPrefixForField properly handles both qualified and unqualified references with correct length checks

2421-2468: LGTM!

Correct implementation of data prefix handling:

  • injectDataPrefix properly transforms chains for both qualified and unqualified references
  • buildAliasWithoutDataPrefix safely operates on a filtered copy, removing the internal data prefix for cleaner user-facing aliases
apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/QueryHistoryPopover.tsx (2)

38-46: LGTM!

The normalization logic is clean and improves SQL display by collapsing whitespace per line while preserving newlines for structure. The increased limit to 500 characters provides better context in history items.


122-136: LGTM!

The conditional rendering correctly prioritizes the title when available (with the query shown as secondary context), while maintaining the original query-focused display when no title exists. The styling differentiation is appropriate.

apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/route.tsx (4)

173-180: LGTM!

The default period calculation correctly respects plan limits while preferring the ideal 7-day default. The logic handles edge cases appropriately.


291-326: LGTM!

The time filter logic correctly handles all cases (from/to, from-only, to-only, period). The non-null assertion on line 311 is safe because the else branch guarantees requestedFromDate was set. The enforcedWhereClause properly enforces tenant isolation and plan-based time limits.


988-1026: LGTM!

The QueryResultsCallouts component provides clear user feedback about result limitations with an actionable upgrade path. The simplur usage correctly handles day/days pluralization.


1028-1033: LGTM!

Clean helper function that encapsulates the callout visibility logic.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Copy link

@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 2 potential issues.

Open in Devin Review

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: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/webapp/app/components/runs/v3/SharedFilters.tsx (1)

455-540: Add exceedsMaxPeriod and maxPeriodDays to the useCallback dependencies.

The callback reads both values (line 458–459), but they're missing from the dependency array. Since exceedsMaxPeriod is recalculated on each render and maxPeriodDays is a prop, omitting them causes the callback to close over stale values when these change.

Proposed fix
   ], [
     activeSection,
     selectedPeriod,
     isCustomDurationValid,
     customValue,
     customUnit,
     fromValue,
     toValue,
     replace,
     onApply,
     onValueChange,
+    exceedsMaxPeriod,
+    maxPeriodDays,
   ]);
🧹 Nitpick comments (2)
internal-packages/clickhouse/schema/014_update_output_error_text_to_extract_data.sql (1)

7-14: Consider extracting repeated toJSONString() call.

toJSONString(output) and toJSONString(error) are each called up to 3 times within their respective expressions. While ClickHouse may optimize this for MATERIALIZED columns computed at insert time, this could be cleaner. Unfortunately, ClickHouse doesn't support CTEs or variable bindings within MATERIALIZED expressions, so this is likely unavoidable—just noting for awareness.

Also applies to: 19-26

apps/webapp/app/components/runs/v3/SharedFilters.tsx (1)

289-308: Prefer type aliases over interface in TSX.

This file uses interfaces for TimeFilterApplyValues and TimeFilterProps; please align with the project rule to use types instead.
As per coding guidelines, use type aliases over interfaces in TS/TSX.

♻️ Proposed refactor
-export interface TimeFilterApplyValues {
+export type TimeFilterApplyValues = {
   period?: string;
   from?: string;
   to?: string;
-}
+};

-export interface TimeFilterProps {
+export type TimeFilterProps = {
   defaultPeriod?: string;
   period?: string;
   from?: string;
   to?: string;
   /** Label name used in the filter display, defaults to "Created" */
   labelName?: string;
   hideLabel?: boolean;
   applyShortcut?: ShortcutDefinition | undefined;
   /** Callback when the user applies a time filter selection, receives the applied values */
   onValueChange?: (values: TimeFilterApplyValues) => void;
   /** When set an upgrade message will be shown if you select a period further back than this number of days */
   maxPeriodDays?: number;
-}
+};
📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9837a90 and 6a34c0b.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (32)
  • apps/webapp/app/components/code/QueryResultsChart.tsx
  • apps/webapp/app/components/code/TSQLResultsTable.tsx
  • apps/webapp/app/components/primitives/AnimatedNumber.tsx
  • apps/webapp/app/components/primitives/Callout.tsx
  • apps/webapp/app/components/primitives/Resizable.tsx
  • apps/webapp/app/components/primitives/charts/Card.tsx
  • apps/webapp/app/components/primitives/charts/ChartLegendCompound.tsx
  • apps/webapp/app/components/primitives/charts/ChartLine.tsx
  • apps/webapp/app/components/primitives/charts/ChartRoot.tsx
  • apps/webapp/app/components/runs/v3/SharedFilters.tsx
  • apps/webapp/app/env.server.ts
  • apps/webapp/app/presenters/v3/QueryPresenter.server.ts
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/QueryHelpSidebar.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/QueryHistoryPopover.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/route.tsx
  • apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query.ai-title.tsx
  • apps/webapp/app/services/queryService.server.ts
  • apps/webapp/app/v3/querySchemas.ts
  • apps/webapp/app/v3/services/aiQueryTitleService.server.ts
  • apps/webapp/package.json
  • internal-packages/clickhouse/schema/014_update_output_error_text_to_extract_data.sql
  • internal-packages/clickhouse/src/client/tsql.ts
  • internal-packages/clickhouse/src/index.ts
  • internal-packages/database/prisma/migrations/20260124203524_customer_query_add_title_remove_cost/migration.sql
  • internal-packages/database/prisma/schema.prisma
  • internal-packages/tsql/src/index.test.ts
  • internal-packages/tsql/src/index.ts
  • internal-packages/tsql/src/query/printer.test.ts
  • internal-packages/tsql/src/query/printer.ts
  • internal-packages/tsql/src/query/printer_context.ts
  • internal-packages/tsql/src/query/schema.ts
  • internal-packages/tsql/src/query/security.test.ts
💤 Files with no reviewable changes (1)
  • apps/webapp/app/env.server.ts
🚧 Files skipped from review as they are similar to previous changes (14)
  • apps/webapp/package.json
  • apps/webapp/app/v3/services/aiQueryTitleService.server.ts
  • internal-packages/tsql/src/query/schema.ts
  • apps/webapp/app/components/code/QueryResultsChart.tsx
  • internal-packages/clickhouse/src/index.ts
  • apps/webapp/app/components/primitives/AnimatedNumber.tsx
  • apps/webapp/app/presenters/v3/QueryPresenter.server.ts
  • apps/webapp/app/components/primitives/charts/ChartRoot.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/QueryHelpSidebar.tsx
  • internal-packages/database/prisma/migrations/20260124203524_customer_query_add_title_remove_cost/migration.sql
  • apps/webapp/app/v3/querySchemas.ts
  • apps/webapp/app/components/code/TSQLResultsTable.tsx
  • apps/webapp/app/components/primitives/Callout.tsx
  • apps/webapp/app/components/primitives/charts/Card.tsx
🧰 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}: Always import tasks from @trigger.dev/sdk, never use @trigger.dev/sdk/v3 or deprecated client.defineJob pattern
Every Trigger.dev task must be exported and have a unique id property with no timeouts in the run function

Files:

  • apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query.ai-title.tsx
  • apps/webapp/app/components/runs/v3/SharedFilters.tsx
  • internal-packages/tsql/src/query/printer.ts
  • internal-packages/tsql/src/query/security.test.ts
  • apps/webapp/app/components/primitives/charts/ChartLine.tsx
  • internal-packages/tsql/src/query/printer.test.ts
  • internal-packages/clickhouse/src/client/tsql.ts
  • internal-packages/tsql/src/query/printer_context.ts
  • internal-packages/tsql/src/index.test.ts
  • apps/webapp/app/services/queryService.server.ts
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/route.tsx
  • apps/webapp/app/components/primitives/Resizable.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/QueryHistoryPopover.tsx
  • apps/webapp/app/components/primitives/charts/ChartLegendCompound.tsx
  • internal-packages/tsql/src/index.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:

  • apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query.ai-title.tsx
  • apps/webapp/app/components/runs/v3/SharedFilters.tsx
  • apps/webapp/app/components/primitives/charts/ChartLine.tsx
  • apps/webapp/app/services/queryService.server.ts
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/route.tsx
  • apps/webapp/app/components/primitives/Resizable.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/QueryHistoryPopover.tsx
  • apps/webapp/app/components/primitives/charts/ChartLegendCompound.tsx
**/*.{ts,tsx,js,jsx}

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

Use function declarations instead of default exports

Import from @trigger.dev/core using subpaths only, never import from root

Files:

  • apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query.ai-title.tsx
  • apps/webapp/app/components/runs/v3/SharedFilters.tsx
  • internal-packages/tsql/src/query/printer.ts
  • internal-packages/tsql/src/query/security.test.ts
  • apps/webapp/app/components/primitives/charts/ChartLine.tsx
  • internal-packages/tsql/src/query/printer.test.ts
  • internal-packages/clickhouse/src/client/tsql.ts
  • internal-packages/tsql/src/query/printer_context.ts
  • internal-packages/tsql/src/index.test.ts
  • apps/webapp/app/services/queryService.server.ts
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/route.tsx
  • apps/webapp/app/components/primitives/Resizable.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/QueryHistoryPopover.tsx
  • apps/webapp/app/components/primitives/charts/ChartLegendCompound.tsx
  • internal-packages/tsql/src/index.ts
apps/webapp/app/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)

Access all environment variables through the env export of env.server.ts instead of directly accessing process.env in the Trigger.dev webapp

Files:

  • apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query.ai-title.tsx
  • apps/webapp/app/components/runs/v3/SharedFilters.tsx
  • apps/webapp/app/components/primitives/charts/ChartLine.tsx
  • apps/webapp/app/services/queryService.server.ts
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/route.tsx
  • apps/webapp/app/components/primitives/Resizable.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/QueryHistoryPopover.tsx
  • apps/webapp/app/components/primitives/charts/ChartLegendCompound.tsx
apps/webapp/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)

apps/webapp/**/*.{ts,tsx}: When importing from @trigger.dev/core in the webapp, use subpath exports from the package.json instead of importing from the root path
Follow the Remix 2.1.0 and Express server conventions when updating the main trigger.dev webapp

Access environment variables via env export from apps/webapp/app/env.server.ts, never use process.env directly

Files:

  • apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query.ai-title.tsx
  • apps/webapp/app/components/runs/v3/SharedFilters.tsx
  • apps/webapp/app/components/primitives/charts/ChartLine.tsx
  • apps/webapp/app/services/queryService.server.ts
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/route.tsx
  • apps/webapp/app/components/primitives/Resizable.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/QueryHistoryPopover.tsx
  • apps/webapp/app/components/primitives/charts/ChartLegendCompound.tsx
**/*.{js,ts,jsx,tsx,json,md,yaml,yml}

📄 CodeRabbit inference engine (AGENTS.md)

Format code using Prettier before committing

Files:

  • apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query.ai-title.tsx
  • apps/webapp/app/components/runs/v3/SharedFilters.tsx
  • internal-packages/tsql/src/query/printer.ts
  • internal-packages/tsql/src/query/security.test.ts
  • apps/webapp/app/components/primitives/charts/ChartLine.tsx
  • internal-packages/tsql/src/query/printer.test.ts
  • internal-packages/clickhouse/src/client/tsql.ts
  • internal-packages/tsql/src/query/printer_context.ts
  • internal-packages/tsql/src/index.test.ts
  • apps/webapp/app/services/queryService.server.ts
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/route.tsx
  • apps/webapp/app/components/primitives/Resizable.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/QueryHistoryPopover.tsx
  • apps/webapp/app/components/primitives/charts/ChartLegendCompound.tsx
  • internal-packages/tsql/src/index.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:

  • internal-packages/tsql/src/query/printer.ts
  • internal-packages/tsql/src/query/security.test.ts
  • internal-packages/tsql/src/query/printer.test.ts
  • internal-packages/clickhouse/src/client/tsql.ts
  • internal-packages/tsql/src/query/printer_context.ts
  • internal-packages/tsql/src/index.test.ts
  • apps/webapp/app/services/queryService.server.ts
  • internal-packages/tsql/src/index.ts
**/*.{test,spec}.{ts,tsx}

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

Use vitest for all tests in the Trigger.dev repository

Files:

  • internal-packages/tsql/src/query/security.test.ts
  • internal-packages/tsql/src/query/printer.test.ts
  • internal-packages/tsql/src/index.test.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

**/*.test.{ts,tsx,js,jsx}: Use vitest exclusively for testing and never mock anything - use testcontainers instead
Place test files next to source files with naming pattern: source file (e.g., MyService.ts) → MyService.test.ts

Files:

  • internal-packages/tsql/src/query/security.test.ts
  • internal-packages/tsql/src/query/printer.test.ts
  • internal-packages/tsql/src/index.test.ts
**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • internal-packages/tsql/src/query/security.test.ts
  • internal-packages/tsql/src/query/printer.test.ts
  • internal-packages/tsql/src/index.test.ts
internal-packages/clickhouse/schema/**/*.sql

📄 CodeRabbit inference engine (CLAUDE.md)

internal-packages/clickhouse/schema/**/*.sql: ClickHouse migrations must use Goose format with -- +goose Up and -- +goose Down markers
Follow ClickHouse naming conventions: raw_ prefix for input tables, _v1, _v2 suffixes for versioning, _mv_v1 suffix for materialized views

Files:

  • internal-packages/clickhouse/schema/014_update_output_error_text_to_extract_data.sql
apps/webapp/app/services/**/*.server.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)

Separate testable services from configuration files; follow the pattern of realtimeClient.server.ts (testable service) and realtimeClientGlobal.server.ts (configuration) in the webapp

Files:

  • apps/webapp/app/services/queryService.server.ts
🧠 Learnings (13)
📚 Learning: 2026-01-15T11:50:06.067Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-15T11:50:06.067Z
Learning: Applies to internal-packages/database/prisma/migrations/**/*.sql : When editing the Prisma schema, remove extraneous migration lines related to specific tables: `_BackgroundWorkerToBackgroundWorkerFile`, `_BackgroundWorkerToTaskQueue`, `_TaskRunToTaskRunTag`, `_WaitpointRunConnections`, `_completedWaitpoints`, `SecretStore_key_idx`, and unrelated `TaskRun` indexes

Applied to files:

  • internal-packages/database/prisma/schema.prisma
  • internal-packages/clickhouse/schema/014_update_output_error_text_to_extract_data.sql
📚 Learning: 2025-12-08T15:19:56.823Z
Learnt from: 0ski
Repo: triggerdotdev/trigger.dev PR: 2760
File: apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam/route.tsx:278-281
Timestamp: 2025-12-08T15:19:56.823Z
Learning: In apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam/route.tsx, the tableState search parameter uses intentional double-encoding: the parameter value contains a URL-encoded URLSearchParams string, so decodeURIComponent(value("tableState") ?? "") is required to fully decode it before parsing with new URLSearchParams(). This pattern allows bundling multiple filter/pagination params as a single search parameter.

Applied to files:

  • apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query.ai-title.tsx
  • internal-packages/tsql/src/query/security.test.ts
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/route.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/QueryHistoryPopover.tsx
📚 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: Applies to apps/webapp/**/*.{ts,tsx} : Follow the Remix 2.1.0 and Express server conventions when updating the main trigger.dev webapp

Applied to files:

  • apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query.ai-title.tsx
📚 Learning: 2025-08-14T10:53:54.526Z
Learnt from: myftija
Repo: triggerdotdev/trigger.dev PR: 2391
File: apps/webapp/app/services/organizationAccessToken.server.ts:50-0
Timestamp: 2025-08-14T10:53:54.526Z
Learning: In the Trigger.dev codebase, token service functions (like revokePersonalAccessToken and revokeOrganizationAccessToken) don't include tenant scoping in their database queries. Instead, authorization and tenant scoping happens at a higher level in the authentication flow (typically in route handlers) before these service functions are called. This is a consistent pattern across both Personal Access Tokens (PATs) and Organization Access Tokens (OATs).

Applied to files:

  • apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query.ai-title.tsx
  • apps/webapp/app/services/queryService.server.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 : Set default maximum duration in trigger.config.ts using `maxDuration` property

Applied to files:

  • apps/webapp/app/components/runs/v3/SharedFilters.tsx
📚 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} : Limit task duration using the `maxDuration` property (in seconds)

Applied to files:

  • apps/webapp/app/components/runs/v3/SharedFilters.tsx
📚 Learning: 2025-07-21T12:52:44.342Z
Learnt from: ericallam
Repo: triggerdotdev/trigger.dev PR: 2284
File: apps/webapp/app/services/realtimeClient.server.ts:111-127
Timestamp: 2025-07-21T12:52:44.342Z
Learning: Electric (the database service used in the realtimeClient) has built-in SQL injection protection and safely handles whereClause parameters passed via URL parameters, so direct string interpolation of runId values into SQL where clauses is safe when using Electric.

Applied to files:

  • internal-packages/tsql/src/query/security.test.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:

  • internal-packages/clickhouse/src/client/tsql.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/trigger-sdk/**/*.{ts,tsx} : In the Trigger.dev SDK (packages/trigger-sdk), prefer isomorphic code like fetch and ReadableStream instead of Node.js-specific code

Applied to files:

  • internal-packages/tsql/src/query/printer_context.ts
📚 Learning: 2026-01-15T11:50:06.067Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-15T11:50:06.067Z
Learning: Applies to internal-packages/clickhouse/schema/**/*.sql : Follow ClickHouse naming conventions: `raw_` prefix for input tables, `_v1`, `_v2` suffixes for versioning, `_mv_v1` suffix for materialized views

Applied to files:

  • internal-packages/clickhouse/schema/014_update_output_error_text_to_extract_data.sql
📚 Learning: 2026-01-15T11:50:06.067Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-15T11:50:06.067Z
Learning: Applies to internal-packages/clickhouse/schema/**/*.sql : ClickHouse migrations must use Goose format with `-- +goose Up` and `-- +goose Down` markers

Applied to files:

  • internal-packages/clickhouse/schema/014_update_output_error_text_to_extract_data.sql
📚 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 internal-packages/database/**/*.{ts,tsx} : Use Prisma for database interactions in internal-packages/database with PostgreSQL

Applied to files:

  • apps/webapp/app/services/queryService.server.ts
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/route.tsx
📚 Learning: 2026-01-12T17:18:09.451Z
Learnt from: matt-aitken
Repo: triggerdotdev/trigger.dev PR: 2870
File: apps/webapp/app/services/redisConcurrencyLimiter.server.ts:56-66
Timestamp: 2026-01-12T17:18:09.451Z
Learning: In `apps/webapp/app/services/redisConcurrencyLimiter.server.ts`, the query concurrency limiter will not be deployed with Redis Cluster mode, so multi-key operations (keyKey and globalKey in different hash slots) are acceptable and will function correctly in standalone Redis mode.

Applied to files:

  • apps/webapp/app/services/queryService.server.ts
🧬 Code graph analysis (7)
apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query.ai-title.tsx (5)
apps/webapp/app/utils/pathBuilder.ts (1)
  • EnvironmentParamSchema (26-28)
apps/webapp/app/models/project.server.ts (1)
  • findProjectBySlug (136-147)
apps/webapp/app/models/runtimeEnvironment.server.ts (1)
  • findEnvironmentBySlug (116-145)
apps/webapp/app/env.server.ts (1)
  • env (1320-1320)
apps/webapp/app/v3/services/aiQueryTitleService.server.ts (1)
  • AIQueryTitleService (15-71)
apps/webapp/app/components/runs/v3/SharedFilters.tsx (3)
apps/webapp/app/components/primitives/Callout.tsx (1)
  • Callout (73-170)
apps/webapp/app/components/primitives/Buttons.tsx (1)
  • LinkButton (335-403)
apps/webapp/app/utils/pathBuilder.ts (1)
  • organizationBillingPath (116-118)
internal-packages/tsql/src/query/printer.test.ts (2)
internal-packages/tsql/src/index.ts (5)
  • createPrinterContext (119-119)
  • TableSchema (113-113)
  • column (81-81)
  • createSchemaRegistry (82-82)
  • PrinterContext (121-121)
internal-packages/tsql/src/query/printer_context.ts (2)
  • createPrinterContext (249-256)
  • PrinterContext (79-214)
internal-packages/clickhouse/src/client/tsql.ts (3)
internal-packages/tsql/src/index.ts (1)
  • WhereClauseCondition (127-127)
internal-packages/clickhouse/src/index.ts (1)
  • WhereClauseCondition (59-59)
internal-packages/tsql/src/query/printer_context.ts (1)
  • WhereClauseCondition (47-47)
internal-packages/tsql/src/query/printer_context.ts (1)
internal-packages/tsql/src/query/schema.ts (2)
  • SchemaRegistry (344-349)
  • FieldMappings (270-270)
internal-packages/tsql/src/index.test.ts (3)
internal-packages/tsql/src/index.ts (4)
  • column (81-81)
  • TableSchema (113-113)
  • WhereClauseCondition (127-127)
  • compileTSQL (538-566)
internal-packages/clickhouse/src/index.ts (2)
  • TableSchema (54-54)
  • WhereClauseCondition (59-59)
internal-packages/tsql/src/query/printer_context.ts (1)
  • WhereClauseCondition (47-47)
apps/webapp/app/components/primitives/charts/ChartLegendCompound.tsx (2)
apps/webapp/app/utils/cn.ts (1)
  • cn (77-79)
apps/webapp/app/components/primitives/AnimatedNumber.tsx (1)
  • AnimatedNumber (22-58)
⏰ 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). (18)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (1, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (7, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (4, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (6, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (5, 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 (6, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (3, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (8, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (2, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (3, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (2, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (5, 8)
  • GitHub Check: units / packages / 🧪 Unit Tests: Packages (1, 1)
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - pnpm)
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - npm)
  • GitHub Check: typecheck / typecheck
🔇 Additional comments (15)
apps/webapp/app/components/primitives/charts/ChartLegendCompound.tsx (3)

20-22: LGTM!

The scrollable prop is well-documented and defaults to false to maintain backward compatibility.

Also applies to: 42-42


134-158: LGTM!

The scrollable container implementation is correct:

  • min-h-0 on flex children properly allows shrinking below content size.
  • shrink-0 on the total row and separator prevents them from being compressed.
  • flex-1 with overflow-y-auto on the items container enables proper scrolling behavior.

159-216: LGTM!

Legend items rendering is clean with proper hover interactions and active state highlighting preserved within the new scrollable structure.

apps/webapp/app/components/primitives/charts/ChartLine.tsx (1)

175-175: LGTM!

Consistent reduction of strokeWidth from 2 to 1 for both Area and Line chart variants results in a cleaner, thinner visual appearance as intended.

Also applies to: 223-223

internal-packages/clickhouse/schema/014_update_output_error_text_to_extract_data.sql (3)

1-1: Goose format and naming conventions followed correctly.

The migration properly uses -- +goose Up and -- +goose Down markers, and the table task_runs_v2 follows the required _v2 suffix convention. Based on learnings and coding guidelines.

Also applies to: 34-34


34-45: Down migration is correctly ordered.

Dropping indexes before columns is the correct order (ClickHouse would fail otherwise), and IF EXISTS guards provide safe rollback behavior.


6-15: ADD COLUMN is correct—these are new columns, not existing ones to modify.

The columns output_text and error_text do not exist in any previous migration (001–013). This migration is their initial creation, so ADD COLUMN is the appropriate statement. The MODIFY COLUMN concern is not applicable here.

The migration correctly uses Goose format (-- +goose Up and -- +goose Down markers) and includes proper rollback operations.

Likely an incorrect or invalid review comment.

apps/webapp/app/components/primitives/Resizable.tsx (3)

29-38: Verify data-handle-orientation is emitted by PanelResizer.
These selectors depend on the library setting that attribute; if it differs, vertical styling won’t apply. Please confirm the actual attribute name and adjust if needed.


44-47: Orientation-specific line indicators look good.
The separate horizontal/vertical indicators and hover transitions are clear and consistent.


50-61: Dot layout switching per orientation is clear.
The hidden/flex toggles make the handle dots adapt cleanly for each orientation.

internal-packages/database/prisma/schema.prisma (1)

2455-2456: Optional query title field looks good.

This aligns with the new AI title feature without forcing existing rows to migrate.

internal-packages/clickhouse/src/client/tsql.ts (1)

42-103: enforcedWhereClause documentation and examples read well.

The API intent is clear and aligns with the enforced tenant/plan guard behavior.

apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/QueryHistoryPopover.tsx (1)

122-135: Title + query rendering looks solid.

The two-line layout with expanded clamp and preserved whitespace fits the new title feature nicely.

internal-packages/tsql/src/query/security.test.ts (1)

55-61: Tests updated cleanly for enforcedWhereClause.

The new default options and optional-guard cases still cover tenant isolation paths well.

internal-packages/tsql/src/query/printer.test.ts (1)

666-1006: Great coverage for JSON textColumn/dataPrefix behavior.

These scenarios should catch regressions in SELECT/WHERE/GROUP BY handling.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

@matt-aitken matt-aitken force-pushed the query-output-error-idempotency branch from 5b56f6b to 713207e Compare January 28, 2026 14:12
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: 3

🤖 Fix all issues with AI agents
In `@apps/webapp/app/components/primitives/Resizable.tsx`:
- Around line 29-61: The current Resizable handle uses non-existent
data-[handle-orientation] selectors; remove those selectors and instead accept
an explicit orientation prop (e.g., orientation: 'horizontal' | 'vertical') on
the Resizable/PanelResizer component and use that prop to conditionally apply
classes and render vertical vs horizontal variants (replace every occurrence of
data-[handle-orientation=vertical] with conditional class logic based on
orientation === 'vertical', and branch rendering for the line indicator and dot
groups accordingly), and update callers of Resizable/PanelResizer to pass the
PanelGroup orientation prop through.

In
`@apps/webapp/app/routes/_app.orgs`.$organizationSlug.projects.$projectParam.env.$envParam.query/route.tsx:
- Around line 291-319: The clip warning is skipped for "to-only" filters because
requestedFromDate remains null; update the logic so "to-only" requests trigger
the clip callout. Specifically, in the code that sets periodClipped (using
requestedFromDate, maxQueryPeriodDate, and timeFilter), change the condition to
treat requestedFromDate === null as clipped (e.g., periodClipped true when
requestedFromDate === null || requestedFromDate < maxQueryPeriodDate) so the
callout appears for to-only filters; keep the rest of the
requestedFromDate/triggeredAtFallback logic intact.

In `@internal-packages/tsql/src/query/printer.ts`:
- Around line 1868-1882: The generated left identifier for text-column
comparisons loses the original table alias when replacing node.left with
leftTextColumn, causing ambiguous/wrong bindings; change the logic that builds
leftTextColumn (from getTextColumnForExpression(node.left)) to preserve the
original qualifier/alias from node.left (e.g., if node.left is a field/column
reference, copy its table alias/qualifier onto the returned text-column
identifier) before calling printIdentifier(leftTextColumn), so printIdentifier
receives a qualified identifier; update getTextColumnForExpression or the code
just after obtaining leftTextColumn to attach the original qualifier and then
call printIdentifier(leftTextColumn) instead of using an unqualified name.
🧹 Nitpick comments (6)
apps/webapp/app/services/queryService.server.ts (1)

121-126: Inconsistent indentation in acquire block.

The concurrency acquisition code has extra indentation that doesn't match the surrounding code structure. This appears to be a formatting inconsistency.

🛠️ Suggested fix
   // Acquire concurrency slot
-    const acquireResult = await queryConcurrencyLimiter.acquire({
-      key: organizationId,
-      requestId,
-      keyLimit: orgLimit,
-      globalLimit: GLOBAL_CONCURRENCY_LIMIT,
-    });
+  const acquireResult = await queryConcurrencyLimiter.acquire({
+    key: organizationId,
+    requestId,
+    keyLimit: orgLimit,
+    globalLimit: GLOBAL_CONCURRENCY_LIMIT,
+  });
apps/webapp/app/components/code/TSQLResultsTable.tsx (1)

674-678: Handle raw string JSON values without losing quotes.

If JSON scalars can arrive as plain strings (not JSON-encoded text), rendering them directly drops quotes and can misrepresent the JSON value. Consider falling back to JSON.stringify when the string isn’t valid JSON text to preserve correct JSON representation.

Proposed tweak
-  const jsonString = typeof value === "string" ? value : JSON.stringify(value);
+  const jsonString =
+    typeof value === "string"
+      ? (() => {
+          try {
+            JSON.parse(value);
+            return value;
+          } catch {
+            return JSON.stringify(value);
+          }
+        })()
+      : JSON.stringify(value);
apps/webapp/app/components/code/QueryResultsChart.tsx (1)

49-58: Prefer a type alias for props to match TS conventions.

♻️ Suggested refactor
-interface QueryResultsChartProps {
+type QueryResultsChartProps = {
   rows: Record<string, unknown>[];
   columns: OutputColumnMetadata[];
   config: ChartConfiguration;
   fullLegend?: boolean;
   /** Callback when "View all" legend button is clicked */
   onViewAllLegendItems?: () => void;
   /** When true, constrains legend to max 50% height with scrolling */
   legendScrollable?: boolean;
-}
+};

As per coding guidelines: **/*.{ts,tsx}: Use types over interfaces for TypeScript`.

internal-packages/clickhouse/src/client/tsql.ts (1)

33-104: Prefer type alias for ExecuteTSQLOptions.

This block was edited; the repo style prefers type aliases over interfaces. Consider switching to a type alias here.

♻️ Suggested refactor
-export interface ExecuteTSQLOptions<TOut extends z.ZodSchema> {
+export type ExecuteTSQLOptions<TOut extends z.ZodSchema> = {
   /** The name of the operation (for logging/tracing) */
   name: string;
   /** The TSQL query string to execute */
   query: string;
@@
-}
+};

As per coding guidelines: Use types over interfaces for TypeScript.

internal-packages/tsql/src/index.ts (1)

450-504: Prefer type alias for CompileTSQLOptions.

This block was edited; the repo style prefers type aliases over interfaces. Consider switching to a type alias.

♻️ Suggested refactor
-export interface CompileTSQLOptions {
+export type CompileTSQLOptions = {
   /** Schema definitions for allowed tables and columns */
   tableSchema: TableSchema[];
@@
-}
+};

As per coding guidelines: Use types over interfaces for TypeScript.

internal-packages/tsql/src/query/printer.test.ts (1)

83-95: Consider extracting a shared enforcedWhereClause test fixture.

The same tenant guard object is repeated across many helper contexts. A shared constant (with per-test overrides as needed) would reduce duplication and make future updates less noisy.

Also applies to: 155-164, 221-229, 481-490, 697-706, 888-897, 1469-1476, 1588-1594, 1813-1820, 2056-2063, 2202-2209, 2901-2920, 3084-3093

📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1376448 and 713207e.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (33)
  • apps/webapp/app/components/code/QueryResultsChart.tsx
  • apps/webapp/app/components/code/TSQLResultsTable.tsx
  • apps/webapp/app/components/primitives/AnimatedNumber.tsx
  • apps/webapp/app/components/primitives/Callout.tsx
  • apps/webapp/app/components/primitives/Resizable.tsx
  • apps/webapp/app/components/primitives/charts/Card.tsx
  • apps/webapp/app/components/primitives/charts/ChartLegendCompound.tsx
  • apps/webapp/app/components/primitives/charts/ChartLine.tsx
  • apps/webapp/app/components/primitives/charts/ChartRoot.tsx
  • apps/webapp/app/components/runs/v3/SharedFilters.tsx
  • apps/webapp/app/env.server.ts
  • apps/webapp/app/presenters/v3/QueryPresenter.server.ts
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/QueryHelpSidebar.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/QueryHistoryPopover.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/route.tsx
  • apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query.ai-title.tsx
  • apps/webapp/app/services/queryService.server.ts
  • apps/webapp/app/v3/querySchemas.ts
  • apps/webapp/app/v3/services/aiQueryTitleService.server.ts
  • apps/webapp/package.json
  • internal-packages/clickhouse/schema/014_update_output_error_text_to_extract_data.sql
  • internal-packages/clickhouse/src/client/tsql.ts
  • internal-packages/clickhouse/src/index.ts
  • internal-packages/clickhouse/src/tsql.test.ts
  • internal-packages/database/prisma/migrations/20260124203524_customer_query_add_title_remove_cost/migration.sql
  • internal-packages/database/prisma/schema.prisma
  • internal-packages/tsql/src/index.test.ts
  • internal-packages/tsql/src/index.ts
  • internal-packages/tsql/src/query/printer.test.ts
  • internal-packages/tsql/src/query/printer.ts
  • internal-packages/tsql/src/query/printer_context.ts
  • internal-packages/tsql/src/query/schema.ts
  • internal-packages/tsql/src/query/security.test.ts
💤 Files with no reviewable changes (1)
  • apps/webapp/app/env.server.ts
🚧 Files skipped from review as they are similar to previous changes (14)
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/QueryHelpSidebar.tsx
  • apps/webapp/app/presenters/v3/QueryPresenter.server.ts
  • internal-packages/tsql/src/query/schema.ts
  • apps/webapp/package.json
  • apps/webapp/app/components/primitives/AnimatedNumber.tsx
  • internal-packages/database/prisma/migrations/20260124203524_customer_query_add_title_remove_cost/migration.sql
  • internal-packages/clickhouse/src/tsql.test.ts
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/QueryHistoryPopover.tsx
  • apps/webapp/app/components/primitives/Callout.tsx
  • internal-packages/clickhouse/schema/014_update_output_error_text_to_extract_data.sql
  • apps/webapp/app/components/primitives/charts/ChartRoot.tsx
  • apps/webapp/app/components/primitives/charts/ChartLine.tsx
  • apps/webapp/app/v3/querySchemas.ts
  • internal-packages/tsql/src/query/printer_context.ts
🧰 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}: Always import tasks from @trigger.dev/sdk, never use @trigger.dev/sdk/v3 or deprecated client.defineJob pattern
Every Trigger.dev task must be exported and have a unique id property with no timeouts in the run function

Files:

  • apps/webapp/app/components/code/TSQLResultsTable.tsx
  • internal-packages/clickhouse/src/index.ts
  • apps/webapp/app/components/code/QueryResultsChart.tsx
  • apps/webapp/app/components/primitives/charts/ChartLegendCompound.tsx
  • internal-packages/tsql/src/query/security.test.ts
  • apps/webapp/app/v3/services/aiQueryTitleService.server.ts
  • internal-packages/tsql/src/query/printer.ts
  • internal-packages/tsql/src/index.test.ts
  • apps/webapp/app/components/primitives/Resizable.tsx
  • apps/webapp/app/components/primitives/charts/Card.tsx
  • internal-packages/clickhouse/src/client/tsql.ts
  • internal-packages/tsql/src/query/printer.test.ts
  • apps/webapp/app/components/runs/v3/SharedFilters.tsx
  • apps/webapp/app/services/queryService.server.ts
  • internal-packages/tsql/src/index.ts
  • apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query.ai-title.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/route.tsx
{packages/core,apps/webapp}/**/*.{ts,tsx}

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

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

Files:

  • apps/webapp/app/components/code/TSQLResultsTable.tsx
  • apps/webapp/app/components/code/QueryResultsChart.tsx
  • apps/webapp/app/components/primitives/charts/ChartLegendCompound.tsx
  • apps/webapp/app/v3/services/aiQueryTitleService.server.ts
  • apps/webapp/app/components/primitives/Resizable.tsx
  • apps/webapp/app/components/primitives/charts/Card.tsx
  • apps/webapp/app/components/runs/v3/SharedFilters.tsx
  • apps/webapp/app/services/queryService.server.ts
  • apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query.ai-title.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/route.tsx
**/*.{ts,tsx,js,jsx}

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

Use function declarations instead of default exports

Import from @trigger.dev/core using subpaths only, never import from root

Files:

  • apps/webapp/app/components/code/TSQLResultsTable.tsx
  • internal-packages/clickhouse/src/index.ts
  • apps/webapp/app/components/code/QueryResultsChart.tsx
  • apps/webapp/app/components/primitives/charts/ChartLegendCompound.tsx
  • internal-packages/tsql/src/query/security.test.ts
  • apps/webapp/app/v3/services/aiQueryTitleService.server.ts
  • internal-packages/tsql/src/query/printer.ts
  • internal-packages/tsql/src/index.test.ts
  • apps/webapp/app/components/primitives/Resizable.tsx
  • apps/webapp/app/components/primitives/charts/Card.tsx
  • internal-packages/clickhouse/src/client/tsql.ts
  • internal-packages/tsql/src/query/printer.test.ts
  • apps/webapp/app/components/runs/v3/SharedFilters.tsx
  • apps/webapp/app/services/queryService.server.ts
  • internal-packages/tsql/src/index.ts
  • apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query.ai-title.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/route.tsx
apps/webapp/app/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)

Access all environment variables through the env export of env.server.ts instead of directly accessing process.env in the Trigger.dev webapp

Files:

  • apps/webapp/app/components/code/TSQLResultsTable.tsx
  • apps/webapp/app/components/code/QueryResultsChart.tsx
  • apps/webapp/app/components/primitives/charts/ChartLegendCompound.tsx
  • apps/webapp/app/v3/services/aiQueryTitleService.server.ts
  • apps/webapp/app/components/primitives/Resizable.tsx
  • apps/webapp/app/components/primitives/charts/Card.tsx
  • apps/webapp/app/components/runs/v3/SharedFilters.tsx
  • apps/webapp/app/services/queryService.server.ts
  • apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query.ai-title.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/route.tsx
apps/webapp/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)

apps/webapp/**/*.{ts,tsx}: When importing from @trigger.dev/core in the webapp, use subpath exports from the package.json instead of importing from the root path
Follow the Remix 2.1.0 and Express server conventions when updating the main trigger.dev webapp

Access environment variables via env export from apps/webapp/app/env.server.ts, never use process.env directly

Files:

  • apps/webapp/app/components/code/TSQLResultsTable.tsx
  • apps/webapp/app/components/code/QueryResultsChart.tsx
  • apps/webapp/app/components/primitives/charts/ChartLegendCompound.tsx
  • apps/webapp/app/v3/services/aiQueryTitleService.server.ts
  • apps/webapp/app/components/primitives/Resizable.tsx
  • apps/webapp/app/components/primitives/charts/Card.tsx
  • apps/webapp/app/components/runs/v3/SharedFilters.tsx
  • apps/webapp/app/services/queryService.server.ts
  • apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query.ai-title.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/route.tsx
**/*.{js,ts,jsx,tsx,json,md,yaml,yml}

📄 CodeRabbit inference engine (AGENTS.md)

Format code using Prettier before committing

Files:

  • apps/webapp/app/components/code/TSQLResultsTable.tsx
  • internal-packages/clickhouse/src/index.ts
  • apps/webapp/app/components/code/QueryResultsChart.tsx
  • apps/webapp/app/components/primitives/charts/ChartLegendCompound.tsx
  • internal-packages/tsql/src/query/security.test.ts
  • apps/webapp/app/v3/services/aiQueryTitleService.server.ts
  • internal-packages/tsql/src/query/printer.ts
  • internal-packages/tsql/src/index.test.ts
  • apps/webapp/app/components/primitives/Resizable.tsx
  • apps/webapp/app/components/primitives/charts/Card.tsx
  • internal-packages/clickhouse/src/client/tsql.ts
  • internal-packages/tsql/src/query/printer.test.ts
  • apps/webapp/app/components/runs/v3/SharedFilters.tsx
  • apps/webapp/app/services/queryService.server.ts
  • internal-packages/tsql/src/index.ts
  • apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query.ai-title.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/route.tsx
**/*.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:

  • internal-packages/clickhouse/src/index.ts
  • internal-packages/tsql/src/query/security.test.ts
  • apps/webapp/app/v3/services/aiQueryTitleService.server.ts
  • internal-packages/tsql/src/query/printer.ts
  • internal-packages/tsql/src/index.test.ts
  • internal-packages/clickhouse/src/client/tsql.ts
  • internal-packages/tsql/src/query/printer.test.ts
  • apps/webapp/app/services/queryService.server.ts
  • internal-packages/tsql/src/index.ts
**/*.{test,spec}.{ts,tsx}

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

Use vitest for all tests in the Trigger.dev repository

Files:

  • internal-packages/tsql/src/query/security.test.ts
  • internal-packages/tsql/src/index.test.ts
  • internal-packages/tsql/src/query/printer.test.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

**/*.test.{ts,tsx,js,jsx}: Use vitest exclusively for testing and never mock anything - use testcontainers instead
Place test files next to source files with naming pattern: source file (e.g., MyService.ts) → MyService.test.ts

Files:

  • internal-packages/tsql/src/query/security.test.ts
  • internal-packages/tsql/src/index.test.ts
  • internal-packages/tsql/src/query/printer.test.ts
**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • internal-packages/tsql/src/query/security.test.ts
  • internal-packages/tsql/src/index.test.ts
  • internal-packages/tsql/src/query/printer.test.ts
apps/webapp/app/v3/services/**/*.server.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)

Organize services in the webapp following the pattern app/v3/services/*/*.server.ts

Files:

  • apps/webapp/app/v3/services/aiQueryTitleService.server.ts
apps/webapp/app/services/**/*.server.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)

Separate testable services from configuration files; follow the pattern of realtimeClient.server.ts (testable service) and realtimeClientGlobal.server.ts (configuration) in the webapp

Files:

  • apps/webapp/app/services/queryService.server.ts
🧠 Learnings (12)
📚 Learning: 2026-01-15T11:50:06.067Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-15T11:50:06.067Z
Learning: Applies to internal-packages/database/prisma/migrations/**/*.sql : When editing the Prisma schema, remove extraneous migration lines related to specific tables: `_BackgroundWorkerToBackgroundWorkerFile`, `_BackgroundWorkerToTaskQueue`, `_TaskRunToTaskRunTag`, `_WaitpointRunConnections`, `_completedWaitpoints`, `SecretStore_key_idx`, and unrelated `TaskRun` indexes

Applied to files:

  • internal-packages/database/prisma/schema.prisma
📚 Learning: 2025-12-08T15:19:56.823Z
Learnt from: 0ski
Repo: triggerdotdev/trigger.dev PR: 2760
File: apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam/route.tsx:278-281
Timestamp: 2025-12-08T15:19:56.823Z
Learning: In apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam/route.tsx, the tableState search parameter uses intentional double-encoding: the parameter value contains a URL-encoded URLSearchParams string, so decodeURIComponent(value("tableState") ?? "") is required to fully decode it before parsing with new URLSearchParams(). This pattern allows bundling multiple filter/pagination params as a single search parameter.

Applied to files:

  • internal-packages/tsql/src/query/security.test.ts
  • apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query.ai-title.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/route.tsx
📚 Learning: 2025-07-21T12:52:44.342Z
Learnt from: ericallam
Repo: triggerdotdev/trigger.dev PR: 2284
File: apps/webapp/app/services/realtimeClient.server.ts:111-127
Timestamp: 2025-07-21T12:52:44.342Z
Learning: Electric (the database service used in the realtimeClient) has built-in SQL injection protection and safely handles whereClause parameters passed via URL parameters, so direct string interpolation of runId values into SQL where clauses is safe when using Electric.

Applied to files:

  • internal-packages/tsql/src/query/security.test.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:

  • internal-packages/clickhouse/src/client/tsql.ts
📚 Learning: 2026-01-28T14:15:09.778Z
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:09.778Z
Learning: In apps/webapp/app/components/runs/v3/SharedFilters.tsx, enforce the maxPeriodDays limit based only on the from date (fromValue) using dateRangeToDays(fromValue) to reflect data retention limits. The to date should be ignored for retention checks. Ensure any retention-window logic or validations rely solely on the fromValue, and update related comments/tests if needed.

Applied to files:

  • apps/webapp/app/components/runs/v3/SharedFilters.tsx
📚 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 : Set default maximum duration in trigger.config.ts using `maxDuration` property

Applied to files:

  • apps/webapp/app/components/runs/v3/SharedFilters.tsx
📚 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} : Limit task duration using the `maxDuration` property (in seconds)

Applied to files:

  • apps/webapp/app/components/runs/v3/SharedFilters.tsx
📚 Learning: 2025-08-14T10:53:54.526Z
Learnt from: myftija
Repo: triggerdotdev/trigger.dev PR: 2391
File: apps/webapp/app/services/organizationAccessToken.server.ts:50-0
Timestamp: 2025-08-14T10:53:54.526Z
Learning: In the Trigger.dev codebase, token service functions (like revokePersonalAccessToken and revokeOrganizationAccessToken) don't include tenant scoping in their database queries. Instead, authorization and tenant scoping happens at a higher level in the authentication flow (typically in route handlers) before these service functions are called. This is a consistent pattern across both Personal Access Tokens (PATs) and Organization Access Tokens (OATs).

Applied to files:

  • apps/webapp/app/services/queryService.server.ts
  • apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query.ai-title.tsx
📚 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 internal-packages/database/**/*.{ts,tsx} : Use Prisma for database interactions in internal-packages/database with PostgreSQL

Applied to files:

  • apps/webapp/app/services/queryService.server.ts
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/route.tsx
📚 Learning: 2026-01-12T17:18:09.451Z
Learnt from: matt-aitken
Repo: triggerdotdev/trigger.dev PR: 2870
File: apps/webapp/app/services/redisConcurrencyLimiter.server.ts:56-66
Timestamp: 2026-01-12T17:18:09.451Z
Learning: In `apps/webapp/app/services/redisConcurrencyLimiter.server.ts`, the query concurrency limiter will not be deployed with Redis Cluster mode, so multi-key operations (keyKey and globalKey in different hash slots) are acceptable and will function correctly in standalone Redis mode.

Applied to files:

  • apps/webapp/app/services/queryService.server.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: Applies to apps/webapp/**/*.{ts,tsx} : Follow the Remix 2.1.0 and Express server conventions when updating the main trigger.dev webapp

Applied to files:

  • apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query.ai-title.tsx
📚 Learning: 2026-01-28T14:15:09.778Z
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:09.778Z
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:

  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/route.tsx
🧬 Code graph analysis (8)
apps/webapp/app/components/primitives/charts/ChartLegendCompound.tsx (2)
apps/webapp/app/utils/cn.ts (1)
  • cn (77-79)
apps/webapp/app/components/primitives/AnimatedNumber.tsx (1)
  • AnimatedNumber (35-71)
apps/webapp/app/v3/services/aiQueryTitleService.server.ts (1)
apps/webapp/app/env.server.ts (1)
  • env (1320-1320)
internal-packages/tsql/src/index.test.ts (4)
apps/webapp/app/services/queryService.server.ts (1)
  • TableSchema (21-21)
internal-packages/clickhouse/src/client/tsql.ts (2)
  • TableSchema (28-28)
  • WhereClauseCondition (28-28)
internal-packages/clickhouse/src/index.ts (2)
  • TableSchema (54-54)
  • WhereClauseCondition (59-59)
internal-packages/tsql/src/query/printer_context.ts (1)
  • WhereClauseCondition (47-47)
internal-packages/clickhouse/src/client/tsql.ts (3)
internal-packages/tsql/src/index.ts (1)
  • WhereClauseCondition (127-127)
internal-packages/clickhouse/src/index.ts (1)
  • WhereClauseCondition (59-59)
internal-packages/tsql/src/query/printer_context.ts (1)
  • WhereClauseCondition (47-47)
internal-packages/tsql/src/query/printer.test.ts (2)
internal-packages/tsql/src/query/printer_context.ts (2)
  • createPrinterContext (249-256)
  • PrinterContext (79-214)
internal-packages/tsql/src/query/schema.ts (3)
  • TableSchema (321-339)
  • column (354-366)
  • createSchemaRegistry (371-387)
apps/webapp/app/components/runs/v3/SharedFilters.tsx (3)
apps/webapp/app/components/primitives/Callout.tsx (1)
  • Callout (73-170)
apps/webapp/app/components/primitives/Buttons.tsx (1)
  • LinkButton (335-403)
apps/webapp/app/utils/pathBuilder.ts (1)
  • organizationBillingPath (116-118)
internal-packages/tsql/src/index.ts (4)
internal-packages/tsql/src/query/printer_context.ts (3)
  • SimpleComparisonCondition (24-29)
  • WhereClauseCondition (47-47)
  • createPrinterContext (249-256)
internal-packages/clickhouse/src/client/tsql.ts (1)
  • WhereClauseCondition (28-28)
internal-packages/clickhouse/src/index.ts (1)
  • WhereClauseCondition (59-59)
internal-packages/tsql/src/query/schema.ts (1)
  • createSchemaRegistry (371-387)
apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/route.tsx (8)
apps/webapp/app/services/platform.v3.server.ts (1)
  • getLimit (241-250)
internal-packages/clickhouse/src/index.ts (1)
  • WhereClauseCondition (59-59)
internal-packages/tsql/src/query/printer_context.ts (1)
  • WhereClauseCondition (47-47)
internal-packages/clickhouse/src/client/noop.ts (1)
  • query (39-53)
apps/webapp/app/routes/_app.orgs.$organizationSlug/route.tsx (1)
  • useCurrentPlan (22-29)
apps/webapp/app/hooks/useSearchParam.ts (1)
  • useSearchParams (7-64)
apps/webapp/app/utils/pathBuilder.ts (1)
  • organizationBillingPath (116-118)
apps/webapp/app/components/primitives/Dialog.tsx (1)
  • DialogHeader (120-120)
⏰ 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 (1, 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 (6, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (3, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (7, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (5, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (1, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (7, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (3, 8)
  • GitHub Check: units / packages / 🧪 Unit Tests: Packages (1, 1)
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - pnpm)
  • GitHub Check: typecheck / typecheck
🔇 Additional comments (34)
apps/webapp/app/components/primitives/charts/Card.tsx (1)

9-9: LGTM! Spacing refinements align with the broader UI consistency updates.

The padding and margin adjustments (pb-2 → pb-1.5, pt-4 → pt-3, mb-4 → mb-3, px-4 → px-3) create a tighter, more compact card layout that complements the chart legend and other layout tweaks in this PR.

Also applies to: 20-20

apps/webapp/app/components/runs/v3/SharedFilters.tsx (9)

1-31: LGTM!

The new imports are all used appropriately within the file for the maxPeriodDays feature implementation.


126-140: LGTM!

The periodToDays and dateRangeToDays helper functions are well-implemented for calculating retention window checks. The implementation correctly focuses on the from date for retention-based limits. Based on learnings: "enforce the maxPeriodDays limit based only on the from date (fromValue) using dateRangeToDays(fromValue) to reflect data retention limits."


374-375: LGTM!

Using a string union type for SectionType aligns with the coding guidelines preference for string unions over enums.


441-453: LGTM!

The exceedsMaxPeriod calculation correctly checks only the from date for date ranges, which aligns with the data retention semantics. Based on learnings: "The maxPeriodDays limit for date ranges should only check the from date (via dateRangeToDays(fromValue)) because it enforces data retention limits."
[approve_code_changes, duplicate_comment]


455-542: LGTM!

The applySelection callback correctly enforces the maxPeriodDays limit with an early return and appropriate error message. The dependency array is properly updated to include exceedsMaxPeriod and maxPeriodDays.


727-790: LGTM!

The quick date presets now consistently set both from and to dates (e.g., "Today" sets the full day range rather than just a start date). This provides a more intuitive UX and aligns with user expectations for date range selections.


799-808: LGTM!

The upgrade Callout is well-implemented with proper conditional rendering, pluralization via simplur, and a clear CTA linking to the organization's billing page.


825-840: LGTM!

Disabling the Apply button when exceedsMaxPeriod is true provides clear feedback to users and works in conjunction with the upgrade Callout to guide users toward upgrading their plan.


401-401: LGTM!

Using useOptionalOrganization is appropriate here since the Callout with the upgrade link should only render when an organization context is available.

apps/webapp/app/services/queryService.server.ts (2)

186-193: LGTM!

The duplicate detection logic correctly compares the query text, scope, and time filter settings. The date comparison using optional chaining properly handles null/undefined cases for database null values.


164-217: LGTM!

The return value handling correctly implements the ExecuteQueryResult contract:

  • Error path returns early with [error, null, null]
  • Success path returns [null, result, queryId] with queryId populated when history tracking is enabled
apps/webapp/app/components/code/TSQLResultsTable.tsx (1)

1136-1151: Row divider styling looks good.

Adds consistent visual separation for rows in the virtualized body.

apps/webapp/app/components/primitives/Resizable.tsx (1)

20-26: Nice API polish with withHandle.
Optional toggle with a safe default keeps current behavior intact.

internal-packages/database/prisma/schema.prisma (1)

2455-2456: LGTM for optional title storage.

apps/webapp/app/v3/services/aiQueryTitleService.server.ts (1)

21-69: Service-level error handling and prompt constraints look solid.

apps/webapp/app/components/primitives/charts/ChartLegendCompound.tsx (1)

134-216: Scrollable legend UX changes look clean and consistent.

apps/webapp/app/components/code/QueryResultsChart.tsx (1)

724-927: Legend scrollable prop is wired consistently through Chart.Root.

apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/route.tsx (2)

603-639: Title generation flow wiring looks good.


302-326: No changes needed—Date objects are explicitly supported in WhereClauseCondition.

The type definitions for SimpleComparisonCondition and BetweenCondition explicitly allow Date | string | number values. The printer automatically serializes Date objects by wrapping them in toDateTime64() calls for ClickHouse compatibility. Using maxQueryPeriodDate directly is correct and follows the documented patterns throughout the codebase.

Likely an incorrect or invalid review comment.

internal-packages/clickhouse/src/client/tsql.ts (2)

10-28: LGTM: WhereClauseCondition re-export keeps the ClickHouse surface aligned.


169-175: LGTM: enforcedWhereClause is now forwarded into compileTSQL.

Ensures enforced guards propagate to the compiler path.

internal-packages/clickhouse/src/index.ts (1)

49-60: LGTM: WhereClauseCondition is exposed from the public entrypoint.

internal-packages/tsql/src/index.ts (1)

551-563: LGTM: undefined enforcedWhereClause entries are stripped before printing.

Nice guard against optional condition keys.

internal-packages/tsql/src/query/security.test.ts (2)

55-61: LGTM: default enforcedWhereClause fixture updated.


414-590: Nice coverage for optional tenant guards.

The org-only / org+project / org+project+env cases read clearly and exercise the new API surface.

internal-packages/tsql/src/query/printer.ts (2)

397-401: LGTM: queryHasGroupBy state is saved/restored for JSON type hints.

The scoped flag avoids leaking GROUP BY context across nested queries.

Also applies to: 553-553


639-679: LGTM: textColumn optimization preserves user-facing names.

Aliasing back to the TSQL column name keeps the UX clean while using the optimized column.

Also applies to: 853-858

internal-packages/tsql/src/query/printer.test.ts (3)

611-663: Good coverage for JSON subfield WHERE handling.

These assertions clearly lock in the no-.:String behavior for WHERE while keeping SELECT/GROUP BY semantics distinct.


666-855: Solid textColumn optimization tests.

Nice breadth across SELECT, WHERE, and edge cases—should catch regressions around textColumn substitution.


857-1007: Nice dataPrefix path + aliasing coverage.

Covers SELECT/WHERE/GROUP BY and alias behavior well, including edge cases.

internal-packages/tsql/src/index.test.ts (3)

12-75: LGTM for the new schema fixtures + base enforcement setup.

These fixtures make the tenant/non-tenant scenarios explicit and improve coverage clarity.


167-231: Nice alignment to WhereClauseCondition in fallback tests.

The updated typings keep fallback fixtures consistent with the public API surface.


516-828: Strong enforcedWhereClause coverage.

Validation, interaction with fallbacks, and security-focused scenarios are well covered.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
internal-packages/tsql/src/query/printer.ts (1)

639-710: Add table qualification to text column references in JOINs.

getTextColumnForField returns only the column name (e.g., "output_text"), discarding table qualification. When multiple tables in a JOIN have the same text column, this produces ambiguous SQL. The function must preserve table context by returning the table alias alongside the column name and rendering both with printIdentifierOrIndex.

The issue affects three locations:

  • Line 644: Bare JSON field selection with text column
  • Line 702: Alias expressions with text column
  • Line 1871: Arithmetic operation left operand comparison with text column

Update getTextColumnForField and getTextColumnForExpression to return Array<string | number> | null instead of string | null, and construct qualified references before rendering (e.g., "runs"."output_text").

🤖 Fix all issues with AI agents
In `@apps/webapp/app/components/runs/v3/SharedFilters.tsx`:
- Around line 799-808: The current Callout for exceedsMaxPeriod only renders
when organization exists, leaving the Apply button disabled with no explanation
if organization is undefined; update the JSX in SharedFilters so that when
exceedsMaxPeriod is true you render a callout regardless of organization: if
organization exists keep the current Callout with the LinkButton CTA (using
organizationBillingPath(organization.slug)), otherwise render a simplified
Callout (no CTA) that displays the same message (e.g., "Your plan allows a
maximum of ${maxPeriodDays} day(s).") so users understand why Apply is disabled;
modify the conditional around Callout (checking only exceedsMaxPeriod) and
branch inside to include or omit the LinkButton accordingly.
🧹 Nitpick comments (2)
internal-packages/clickhouse/src/client/tsql.ts (1)

33-104: Prefer a type alias over an interface for ExecuteTSQLOptions.

This keeps the public surface consistent with the project’s TypeScript style guidance.

♻️ Suggested refactor
-export interface ExecuteTSQLOptions<TOut extends z.ZodSchema> {
+export type ExecuteTSQLOptions<TOut extends z.ZodSchema> = {
   /** The name of the operation (for logging/tracing) */
   name: string;
   ...
-}
+};

As per coding guidelines, "Use types over interfaces for TypeScript".

internal-packages/tsql/src/index.ts (1)

450-504: Prefer a type alias over interface for CompileTSQLOptions.

This aligns the public API with the TS style guidance.

♻️ Suggested refactor
-export interface CompileTSQLOptions {
+export type CompileTSQLOptions = {
   /** Schema definitions for allowed tables and columns */
   tableSchema: TableSchema[];
   ...
-}
+};

As per coding guidelines, "Use types over interfaces for TypeScript".

📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1376448 and 32a1ed4.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (34)
  • apps/webapp/app/components/code/QueryResultsChart.tsx
  • apps/webapp/app/components/code/TSQLResultsTable.tsx
  • apps/webapp/app/components/primitives/AnimatedNumber.tsx
  • apps/webapp/app/components/primitives/Callout.tsx
  • apps/webapp/app/components/primitives/Resizable.tsx
  • apps/webapp/app/components/primitives/charts/Card.tsx
  • apps/webapp/app/components/primitives/charts/ChartLegendCompound.tsx
  • apps/webapp/app/components/primitives/charts/ChartLine.tsx
  • apps/webapp/app/components/primitives/charts/ChartRoot.tsx
  • apps/webapp/app/components/runs/v3/SharedFilters.tsx
  • apps/webapp/app/env.server.ts
  • apps/webapp/app/presenters/v3/QueryPresenter.server.ts
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/ExamplesContent.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/QueryHelpSidebar.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/QueryHistoryPopover.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/route.tsx
  • apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query.ai-title.tsx
  • apps/webapp/app/services/queryService.server.ts
  • apps/webapp/app/v3/querySchemas.ts
  • apps/webapp/app/v3/services/aiQueryTitleService.server.ts
  • apps/webapp/package.json
  • internal-packages/clickhouse/schema/014_update_output_error_text_to_extract_data.sql
  • internal-packages/clickhouse/src/client/tsql.ts
  • internal-packages/clickhouse/src/index.ts
  • internal-packages/clickhouse/src/tsql.test.ts
  • internal-packages/database/prisma/migrations/20260124203524_customer_query_add_title_remove_cost/migration.sql
  • internal-packages/database/prisma/schema.prisma
  • internal-packages/tsql/src/index.test.ts
  • internal-packages/tsql/src/index.ts
  • internal-packages/tsql/src/query/printer.test.ts
  • internal-packages/tsql/src/query/printer.ts
  • internal-packages/tsql/src/query/printer_context.ts
  • internal-packages/tsql/src/query/schema.ts
  • internal-packages/tsql/src/query/security.test.ts
💤 Files with no reviewable changes (1)
  • apps/webapp/app/env.server.ts
🚧 Files skipped from review as they are similar to previous changes (14)
  • apps/webapp/app/components/code/TSQLResultsTable.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/QueryHistoryPopover.tsx
  • apps/webapp/app/components/primitives/Callout.tsx
  • apps/webapp/package.json
  • apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query.ai-title.tsx
  • apps/webapp/app/v3/services/aiQueryTitleService.server.ts
  • internal-packages/tsql/src/query/schema.ts
  • internal-packages/clickhouse/src/index.ts
  • apps/webapp/app/components/primitives/Resizable.tsx
  • apps/webapp/app/components/primitives/charts/ChartRoot.tsx
  • apps/webapp/app/components/primitives/charts/Card.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/QueryHelpSidebar.tsx
  • internal-packages/clickhouse/schema/014_update_output_error_text_to_extract_data.sql
  • apps/webapp/app/components/primitives/charts/ChartLine.tsx
🧰 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}: Always import tasks from @trigger.dev/sdk, never use @trigger.dev/sdk/v3 or deprecated client.defineJob pattern
Every Trigger.dev task must be exported and have a unique id property with no timeouts in the run function

Files:

  • apps/webapp/app/components/primitives/AnimatedNumber.tsx
  • apps/webapp/app/presenters/v3/QueryPresenter.server.ts
  • apps/webapp/app/components/primitives/charts/ChartLegendCompound.tsx
  • internal-packages/tsql/src/query/security.test.ts
  • internal-packages/tsql/src/index.test.ts
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/ExamplesContent.tsx
  • internal-packages/tsql/src/query/printer_context.ts
  • internal-packages/tsql/src/query/printer.ts
  • apps/webapp/app/components/code/QueryResultsChart.tsx
  • internal-packages/clickhouse/src/client/tsql.ts
  • apps/webapp/app/components/runs/v3/SharedFilters.tsx
  • apps/webapp/app/services/queryService.server.ts
  • internal-packages/tsql/src/index.ts
  • internal-packages/clickhouse/src/tsql.test.ts
  • internal-packages/tsql/src/query/printer.test.ts
  • apps/webapp/app/v3/querySchemas.ts
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/route.tsx
{packages/core,apps/webapp}/**/*.{ts,tsx}

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

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

Files:

  • apps/webapp/app/components/primitives/AnimatedNumber.tsx
  • apps/webapp/app/presenters/v3/QueryPresenter.server.ts
  • apps/webapp/app/components/primitives/charts/ChartLegendCompound.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/ExamplesContent.tsx
  • apps/webapp/app/components/code/QueryResultsChart.tsx
  • apps/webapp/app/components/runs/v3/SharedFilters.tsx
  • apps/webapp/app/services/queryService.server.ts
  • apps/webapp/app/v3/querySchemas.ts
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/route.tsx
**/*.{ts,tsx,js,jsx}

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

Use function declarations instead of default exports

Import from @trigger.dev/core using subpaths only, never import from root

Files:

  • apps/webapp/app/components/primitives/AnimatedNumber.tsx
  • apps/webapp/app/presenters/v3/QueryPresenter.server.ts
  • apps/webapp/app/components/primitives/charts/ChartLegendCompound.tsx
  • internal-packages/tsql/src/query/security.test.ts
  • internal-packages/tsql/src/index.test.ts
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/ExamplesContent.tsx
  • internal-packages/tsql/src/query/printer_context.ts
  • internal-packages/tsql/src/query/printer.ts
  • apps/webapp/app/components/code/QueryResultsChart.tsx
  • internal-packages/clickhouse/src/client/tsql.ts
  • apps/webapp/app/components/runs/v3/SharedFilters.tsx
  • apps/webapp/app/services/queryService.server.ts
  • internal-packages/tsql/src/index.ts
  • internal-packages/clickhouse/src/tsql.test.ts
  • internal-packages/tsql/src/query/printer.test.ts
  • apps/webapp/app/v3/querySchemas.ts
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/route.tsx
apps/webapp/app/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)

Access all environment variables through the env export of env.server.ts instead of directly accessing process.env in the Trigger.dev webapp

Files:

  • apps/webapp/app/components/primitives/AnimatedNumber.tsx
  • apps/webapp/app/presenters/v3/QueryPresenter.server.ts
  • apps/webapp/app/components/primitives/charts/ChartLegendCompound.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/ExamplesContent.tsx
  • apps/webapp/app/components/code/QueryResultsChart.tsx
  • apps/webapp/app/components/runs/v3/SharedFilters.tsx
  • apps/webapp/app/services/queryService.server.ts
  • apps/webapp/app/v3/querySchemas.ts
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/route.tsx
apps/webapp/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)

apps/webapp/**/*.{ts,tsx}: When importing from @trigger.dev/core in the webapp, use subpath exports from the package.json instead of importing from the root path
Follow the Remix 2.1.0 and Express server conventions when updating the main trigger.dev webapp

Access environment variables via env export from apps/webapp/app/env.server.ts, never use process.env directly

Files:

  • apps/webapp/app/components/primitives/AnimatedNumber.tsx
  • apps/webapp/app/presenters/v3/QueryPresenter.server.ts
  • apps/webapp/app/components/primitives/charts/ChartLegendCompound.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/ExamplesContent.tsx
  • apps/webapp/app/components/code/QueryResultsChart.tsx
  • apps/webapp/app/components/runs/v3/SharedFilters.tsx
  • apps/webapp/app/services/queryService.server.ts
  • apps/webapp/app/v3/querySchemas.ts
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/route.tsx
**/*.{js,ts,jsx,tsx,json,md,yaml,yml}

📄 CodeRabbit inference engine (AGENTS.md)

Format code using Prettier before committing

Files:

  • apps/webapp/app/components/primitives/AnimatedNumber.tsx
  • apps/webapp/app/presenters/v3/QueryPresenter.server.ts
  • apps/webapp/app/components/primitives/charts/ChartLegendCompound.tsx
  • internal-packages/tsql/src/query/security.test.ts
  • internal-packages/tsql/src/index.test.ts
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/ExamplesContent.tsx
  • internal-packages/tsql/src/query/printer_context.ts
  • internal-packages/tsql/src/query/printer.ts
  • apps/webapp/app/components/code/QueryResultsChart.tsx
  • internal-packages/clickhouse/src/client/tsql.ts
  • apps/webapp/app/components/runs/v3/SharedFilters.tsx
  • apps/webapp/app/services/queryService.server.ts
  • internal-packages/tsql/src/index.ts
  • internal-packages/clickhouse/src/tsql.test.ts
  • internal-packages/tsql/src/query/printer.test.ts
  • apps/webapp/app/v3/querySchemas.ts
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/route.tsx
**/*.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:

  • apps/webapp/app/presenters/v3/QueryPresenter.server.ts
  • internal-packages/tsql/src/query/security.test.ts
  • internal-packages/tsql/src/index.test.ts
  • internal-packages/tsql/src/query/printer_context.ts
  • internal-packages/tsql/src/query/printer.ts
  • internal-packages/clickhouse/src/client/tsql.ts
  • apps/webapp/app/services/queryService.server.ts
  • internal-packages/tsql/src/index.ts
  • internal-packages/clickhouse/src/tsql.test.ts
  • internal-packages/tsql/src/query/printer.test.ts
  • apps/webapp/app/v3/querySchemas.ts
**/*.{test,spec}.{ts,tsx}

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

Use vitest for all tests in the Trigger.dev repository

Files:

  • internal-packages/tsql/src/query/security.test.ts
  • internal-packages/tsql/src/index.test.ts
  • internal-packages/clickhouse/src/tsql.test.ts
  • internal-packages/tsql/src/query/printer.test.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

**/*.test.{ts,tsx,js,jsx}: Use vitest exclusively for testing and never mock anything - use testcontainers instead
Place test files next to source files with naming pattern: source file (e.g., MyService.ts) → MyService.test.ts

Files:

  • internal-packages/tsql/src/query/security.test.ts
  • internal-packages/tsql/src/index.test.ts
  • internal-packages/clickhouse/src/tsql.test.ts
  • internal-packages/tsql/src/query/printer.test.ts
**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • internal-packages/tsql/src/query/security.test.ts
  • internal-packages/tsql/src/index.test.ts
  • internal-packages/clickhouse/src/tsql.test.ts
  • internal-packages/tsql/src/query/printer.test.ts
apps/webapp/app/services/**/*.server.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)

Separate testable services from configuration files; follow the pattern of realtimeClient.server.ts (testable service) and realtimeClientGlobal.server.ts (configuration) in the webapp

Files:

  • apps/webapp/app/services/queryService.server.ts
internal-packages/database/prisma/migrations/**/*.sql

📄 CodeRabbit inference engine (CLAUDE.md)

internal-packages/database/prisma/migrations/**/*.sql: When editing the Prisma schema, remove extraneous migration lines related to specific tables: _BackgroundWorkerToBackgroundWorkerFile, _BackgroundWorkerToTaskQueue, _TaskRunToTaskRunTag, _WaitpointRunConnections, _completedWaitpoints, SecretStore_key_idx, and unrelated TaskRun indexes
Database indexes must use CONCURRENTLY to avoid table locks and must be in their own separate migration file

Files:

  • internal-packages/database/prisma/migrations/20260124203524_customer_query_add_title_remove_cost/migration.sql
🧠 Learnings (14)
📚 Learning: 2026-01-15T11:50:06.067Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-15T11:50:06.067Z
Learning: Applies to internal-packages/database/prisma/migrations/**/*.sql : When editing the Prisma schema, remove extraneous migration lines related to specific tables: `_BackgroundWorkerToBackgroundWorkerFile`, `_BackgroundWorkerToTaskQueue`, `_TaskRunToTaskRunTag`, `_WaitpointRunConnections`, `_completedWaitpoints`, `SecretStore_key_idx`, and unrelated `TaskRun` indexes

Applied to files:

  • internal-packages/database/prisma/schema.prisma
  • internal-packages/database/prisma/migrations/20260124203524_customer_query_add_title_remove_cost/migration.sql
📚 Learning: 2025-12-08T15:19:56.823Z
Learnt from: 0ski
Repo: triggerdotdev/trigger.dev PR: 2760
File: apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam/route.tsx:278-281
Timestamp: 2025-12-08T15:19:56.823Z
Learning: In apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam/route.tsx, the tableState search parameter uses intentional double-encoding: the parameter value contains a URL-encoded URLSearchParams string, so decodeURIComponent(value("tableState") ?? "") is required to fully decode it before parsing with new URLSearchParams(). This pattern allows bundling multiple filter/pagination params as a single search parameter.

Applied to files:

  • internal-packages/tsql/src/query/security.test.ts
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/ExamplesContent.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/route.tsx
📚 Learning: 2025-07-21T12:52:44.342Z
Learnt from: ericallam
Repo: triggerdotdev/trigger.dev PR: 2284
File: apps/webapp/app/services/realtimeClient.server.ts:111-127
Timestamp: 2025-07-21T12:52:44.342Z
Learning: Electric (the database service used in the realtimeClient) has built-in SQL injection protection and safely handles whereClause parameters passed via URL parameters, so direct string interpolation of runId values into SQL where clauses is safe when using Electric.

Applied to files:

  • internal-packages/tsql/src/query/security.test.ts
  • internal-packages/clickhouse/src/tsql.test.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: Applies to apps/webapp/**/*.{ts,tsx} : Follow the Remix 2.1.0 and Express server conventions when updating the main trigger.dev webapp

Applied to files:

  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/ExamplesContent.tsx
📚 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/trigger-sdk/**/*.{ts,tsx} : In the Trigger.dev SDK (packages/trigger-sdk), prefer isomorphic code like fetch and ReadableStream instead of Node.js-specific code

Applied to files:

  • internal-packages/tsql/src/query/printer_context.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:

  • internal-packages/clickhouse/src/client/tsql.ts
  • internal-packages/clickhouse/src/tsql.test.ts
📚 Learning: 2026-01-28T14:15:09.778Z
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:09.778Z
Learning: In apps/webapp/app/components/runs/v3/SharedFilters.tsx, enforce the maxPeriodDays limit based only on the from date (fromValue) using dateRangeToDays(fromValue) to reflect data retention limits. The to date should be ignored for retention checks. Ensure any retention-window logic or validations rely solely on the fromValue, and update related comments/tests if needed.

Applied to files:

  • apps/webapp/app/components/runs/v3/SharedFilters.tsx
📚 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 : Set default maximum duration in trigger.config.ts using `maxDuration` property

Applied to files:

  • apps/webapp/app/components/runs/v3/SharedFilters.tsx
📚 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} : Limit task duration using the `maxDuration` property (in seconds)

Applied to files:

  • apps/webapp/app/components/runs/v3/SharedFilters.tsx
📚 Learning: 2025-08-14T10:53:54.526Z
Learnt from: myftija
Repo: triggerdotdev/trigger.dev PR: 2391
File: apps/webapp/app/services/organizationAccessToken.server.ts:50-0
Timestamp: 2025-08-14T10:53:54.526Z
Learning: In the Trigger.dev codebase, token service functions (like revokePersonalAccessToken and revokeOrganizationAccessToken) don't include tenant scoping in their database queries. Instead, authorization and tenant scoping happens at a higher level in the authentication flow (typically in route handlers) before these service functions are called. This is a consistent pattern across both Personal Access Tokens (PATs) and Organization Access Tokens (OATs).

Applied to files:

  • apps/webapp/app/services/queryService.server.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 internal-packages/database/**/*.{ts,tsx} : Use Prisma for database interactions in internal-packages/database with PostgreSQL

Applied to files:

  • apps/webapp/app/services/queryService.server.ts
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/route.tsx
📚 Learning: 2026-01-12T17:18:09.451Z
Learnt from: matt-aitken
Repo: triggerdotdev/trigger.dev PR: 2870
File: apps/webapp/app/services/redisConcurrencyLimiter.server.ts:56-66
Timestamp: 2026-01-12T17:18:09.451Z
Learning: In `apps/webapp/app/services/redisConcurrencyLimiter.server.ts`, the query concurrency limiter will not be deployed with Redis Cluster mode, so multi-key operations (keyKey and globalKey in different hash slots) are acceptable and will function correctly in standalone Redis mode.

Applied to files:

  • apps/webapp/app/services/queryService.server.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} : Scope idempotency keys globally or to current run using the scope parameter

Applied to files:

  • apps/webapp/app/v3/querySchemas.ts
📚 Learning: 2026-01-28T14:15:09.778Z
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:09.778Z
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:

  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/route.tsx
🧬 Code graph analysis (9)
apps/webapp/app/components/primitives/charts/ChartLegendCompound.tsx (2)
apps/webapp/app/utils/cn.ts (1)
  • cn (77-79)
apps/webapp/app/components/primitives/AnimatedNumber.tsx (1)
  • AnimatedNumber (35-71)
internal-packages/tsql/src/index.test.ts (3)
internal-packages/tsql/src/index.ts (3)
  • TableSchema (113-113)
  • WhereClauseCondition (127-127)
  • compileTSQL (538-566)
internal-packages/clickhouse/src/index.ts (2)
  • TableSchema (54-54)
  • WhereClauseCondition (59-59)
internal-packages/tsql/src/query/printer_context.ts (1)
  • WhereClauseCondition (47-47)
internal-packages/tsql/src/query/printer.ts (4)
internal-packages/tsql/src/query/ast.ts (3)
  • Alias (372-378)
  • Field (468-472)
  • Expression (47-78)
internal-packages/tsql/src/query/schema.ts (3)
  • TableSchema (321-339)
  • column (354-366)
  • ColumnSchema (52-253)
internal-packages/tsql/src/query/errors.ts (1)
  • QueryError (43-45)
internal-packages/tsql/src/query/printer_context.ts (1)
  • WhereClauseCondition (47-47)
internal-packages/clickhouse/src/client/tsql.ts (1)
internal-packages/tsql/src/query/printer_context.ts (1)
  • WhereClauseCondition (47-47)
apps/webapp/app/components/runs/v3/SharedFilters.tsx (3)
apps/webapp/app/components/primitives/Callout.tsx (1)
  • Callout (73-170)
apps/webapp/app/components/primitives/Buttons.tsx (1)
  • LinkButton (335-403)
apps/webapp/app/utils/pathBuilder.ts (1)
  • organizationBillingPath (116-118)
apps/webapp/app/services/queryService.server.ts (4)
internal-packages/clickhouse/src/client/tsql.ts (1)
  • TSQLQueryResult (133-133)
internal-packages/clickhouse/src/index.ts (2)
  • TSQLQueryResult (55-55)
  • QueryError (64-64)
apps/webapp/app/services/queryConcurrencyLimiter.server.ts (2)
  • queryConcurrencyLimiter (19-22)
  • GLOBAL_CONCURRENCY_LIMIT (28-28)
internal-packages/tsql/src/query/errors.ts (1)
  • QueryError (43-45)
internal-packages/tsql/src/index.ts (4)
internal-packages/tsql/src/query/printer_context.ts (3)
  • SimpleComparisonCondition (24-29)
  • WhereClauseCondition (47-47)
  • createPrinterContext (249-256)
internal-packages/clickhouse/src/client/tsql.ts (1)
  • WhereClauseCondition (28-28)
internal-packages/clickhouse/src/index.ts (1)
  • WhereClauseCondition (59-59)
internal-packages/tsql/src/query/schema.ts (1)
  • createSchemaRegistry (371-387)
apps/webapp/app/v3/querySchemas.ts (1)
internal-packages/tsql/src/query/schema.ts (1)
  • column (354-366)
apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/route.tsx (7)
apps/webapp/app/services/platform.v3.server.ts (1)
  • getLimit (241-250)
internal-packages/clickhouse/src/client/tsql.ts (1)
  • WhereClauseCondition (28-28)
internal-packages/clickhouse/src/index.ts (2)
  • WhereClauseCondition (59-59)
  • OutputColumnMetadata (61-61)
internal-packages/tsql/src/query/printer_context.ts (1)
  • WhereClauseCondition (47-47)
apps/webapp/app/presenters/v3/QueryPresenter.server.ts (1)
  • QueryHistoryItem (5-17)
apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query.ai-title.tsx (1)
  • action (17-68)
apps/webapp/app/routes/_app.orgs.$organizationSlug/route.tsx (1)
  • useCurrentPlan (22-29)
⏰ 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). (1)
  • GitHub Check: units / internal / 📊 Merge Reports
🔇 Additional comments (51)
apps/webapp/app/components/primitives/AnimatedNumber.tsx (1)

4-61: Sanitization + locale formatting looks solid.

The sanitizeDecimals + useMemo flow keeps toLocaleString safe and predictable while preserving the auto-detection behavior.

internal-packages/database/prisma/migrations/20260124203524_customer_query_add_title_remove_cost/migration.sql (1)

1-7: LGTM for the column swap. Clean, idempotent add/drop with no index side effects.

apps/webapp/app/presenters/v3/QueryPresenter.server.ts (2)

5-16: Good addition of title to the public history shape.


21-53: Selection and mapping include title consistently.

internal-packages/database/prisma/schema.prisma (1)

2443-2457: Schema update aligns with title usage.

apps/webapp/app/components/runs/v3/SharedFilters.tsx (4)

126-140: LGTM!

The helper functions are well-implemented. periodToDays correctly uses parse-duration and safely returns 0 for invalid input. dateRangeToDays appropriately calculates days from a given date to now.


441-453: Correct implementation per retention semantics.

The exceedsMaxPeriod check correctly only evaluates fromValue for date ranges, aligning with the data retention limit behavior where only how far back in history matters.

Based on learnings: "In apps/webapp/app/components/runs/v3/SharedFilters.tsx, enforce the maxPeriodDays limit based only on the from date (fromValue) using dateRangeToDays(fromValue) to reflect data retention limits."


727-790: LGTM!

Good improvements to the quick date buttons:

  • Grid layout reorganization for better visual hierarchy
  • Using endOfDay(), endOfWeek(), and endOfMonth() for the "to" values ensures the full day/week/month is captured in the date range.

15-29: LGTM!

New imports are appropriate for the added functionality - simplur for pluralization, Callout and LinkButton for the upgrade prompt UI, and useOptionalOrganization with organizationBillingPath for the billing CTA.

apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/ExamplesContent.tsx (1)

51-51: LGTM!

The column name change from created_at to triggered_at correctly aligns with the user-facing schema defined in querySchemas.ts and makes this example consistent with the other example queries in the file.

apps/webapp/app/components/code/QueryResultsChart.tsx (2)

8-43: LGTM!

The expanded color palette is well-organized with clear comment sections (primary, extended, additional) making it easy to understand and maintain. The 30 distinct colors provide good coverage for large datasets.


56-57: LGTM!

The legendScrollable prop is properly typed, has a sensible default value, and is correctly forwarded to Chart.Root in both the bar and line chart variants.

Also applies to: 730-731, 901-901, 926-926

apps/webapp/app/v3/querySchemas.ts (2)

170-178: LGTM!

The idempotency key schema changes are well-structured:

  • idempotency_key now correctly maps to the ClickHouse column idempotency_key_user
  • New idempotency_key_scope field has a clear description explaining the scope behavior and includes appropriate allowedValues

332-354: LGTM!

The JSON column enhancements are well-documented with inline comments. The textColumn and dataPrefix properties enable performance optimizations by using pre-materialized text columns and handling the internal {"data": ...} wrapper transparently.

internal-packages/tsql/src/query/security.test.ts (2)

55-62: LGTM!

The defaultOptions correctly demonstrates the new enforcedWhereClause structure with explicit equality conditions for tenant guards. This is a clean API that makes the tenant filtering behavior explicit and configurable.


403-589: LGTM!

The "Optional Tenant Filters" test suite comprehensively validates the new enforcedWhereClause behavior:

  • Organization ID is always required
  • Project and environment IDs can be selectively omitted for cross-project/environment queries
  • Security guarantees are maintained even with partial filters

The helper function getWhereClause is a nice utility for precise testing of WHERE clause content.

internal-packages/clickhouse/src/tsql.test.ts (2)

105-115: LGTM!

The test correctly demonstrates the new enforcedWhereClause API pattern for tenant filtering. The structure is clear and consistent across all test cases.


506-798: LGTM!

The "Optional Tenant Filter Tests" provide excellent coverage of the flexible tenant filtering capability:

  • Cross-project queries (omitting project_id and environment_id)
  • Cross-environment queries (omitting only environment_id)
  • Organization isolation is always enforced
  • OR clause bypass prevention with org-only filters

These integration tests validate that the security guarantees hold in practice against a real ClickHouse instance.

apps/webapp/app/components/primitives/charts/ChartLegendCompound.tsx (4)

20-22: LGTM!

The new scrollable prop is properly typed and documented with a clear JSDoc comment explaining its purpose.

Also applies to: 42-43


134-140: LGTM!

The conditional styling correctly applies max-h-[50%] and min-h-0 when scrollable is enabled. The min-h-0 is essential for allowing flex children to shrink below their content size, enabling the scroll behavior.


159-216: LGTM!

The legend items are now properly wrapped in a scrollable container. The structure correctly uses:

  • min-h-0 to allow shrinking
  • flex-1 to fill available space
  • overflow-y-auto for scrolling when content overflows

The "View more" row is appropriately included inside the scrollable area.


155-158: Plugin is properly configured.

The tailwind-scrollbar plugin (v3.0.1) is installed in apps/webapp/package.json and required in tailwind.config.js. The classes scrollbar-thin, scrollbar-track-transparent, and scrollbar-thumb-charcoal-600 are standard utilities from the plugin using the custom charcoal color palette defined in the theme. No additional configuration is needed.

internal-packages/tsql/src/query/printer.ts (6)

397-401: Good guard for JSON subfield hints tied to GROUP BY.

Tracking and restoring queryHasGroupBy keeps JSON type-hint behavior consistent across nested queries.

Also applies to: 551-553


853-857: SELECT * expansion correctly prefers text columns for JSON fields.

Nice addition that preserves user-facing names while using optimized storage.


1578-1604: Tenant column enforcement validation looks good.

Clear error path when organization scoping is missing.


1606-1638: Date normalization for enforced conditions is straightforward and consistent.

The UTC DateTime64 formatting path is clean and predictable.


2296-2307: Nice separation of WHERE comparison context.

This makes the JSON hinting logic much easier to reason about.


2395-2468: dataPrefix utilities are clean and easy to follow.

Nice encapsulation of prefix injection and alias cleanup.

internal-packages/tsql/src/index.test.ts (3)

12-74: Test schema setup for enforcedWhereClause is clear.

Good fixtures for tenant/non-tenant scenarios.


167-243: Fallback tests updated cleanly for WhereClauseCondition.

Nice alignment with the new condition type.


516-828: Nice coverage for enforcedWhereClause validation and interactions.

The validation, operator, and fallback-interaction cases are thorough.

internal-packages/tsql/src/query/printer.test.ts (4)

83-94: Consistent enforcedWhereClause wiring across test contexts.

Good to see uniform setup across helpers and inline contexts.

Also applies to: 155-164, 221-229, 248-258, 483-491, 1150-1157, 1469-1477, 1587-1595, 1813-1821, 2056-2064, 2202-2210, 2615-2621, 2633-2639, 2771-2784, 2899-2908, 2913-2920, 3086-3093


611-663: Great coverage for JSON subfield .:String behavior.

These cases pin down SELECT/GROUP BY vs WHERE differences well.


666-855: Text-column optimization tests look thorough.

Covers SELECT, WHERE, and edge cases nicely.


857-1007: dataPrefix tests cover key SELECT/WHERE/GROUP BY cases.

Good coverage of aliasing and nested-path behavior.

internal-packages/tsql/src/query/printer_context.ts (4)

95-118: EnforcedWhereClause storage on context is clear and well-documented.

Nice to see the enforcement intent baked into the context.


193-199: Child context correctly inherits enforcedWhereClause.

This keeps enforcement consistent across subqueries.


219-243: PrinterContextOptions docs for enforcedWhereClause are clear.

The example is helpful for callers.


249-255: createPrinterContext wiring looks good.

Clean handoff of enforcedWhereClause into the context.

internal-packages/clickhouse/src/client/tsql.ts (1)

5-5: Enforced WHERE clause propagation is consistent.

Docs/examples, type re-exports, and compile-time wiring all align with the new enforcedWhereClause path.

Also applies to: 17-28, 139-175, 294-305

apps/webapp/app/services/queryService.server.ts (1)

89-95: QueryId propagation + dedupe reuse looks good.

Returning queryId and reusing lastQuery.id avoids duplicate history entries and gives callers a stable reference.

Also applies to: 169-217

internal-packages/tsql/src/index.ts (3)

26-32: Centralized re-exports for WhereClauseCondition are clear.

Exposing the condition types from the index makes the public API easier to consume.

Also applies to: 117-128


316-367: Fallback helpers updated cleanly to WhereClauseCondition.

The type updates for fallback ops and injection stay consistent with the new condition model.

Also applies to: 377-413


542-565: Filtering undefined enforcedWhereClause before printer context is a good guard.

Helps avoid accidental empty guards propagating into the printer.

apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/route.tsx (7)

1-73: Import updates align with the new query UX features.


165-180: Plan-aware default period is a nice touch.

It keeps the initial query window within plan limits while preserving the 7‑day ideal.


282-327: Retention clipping uses the right “from” basis.

Using requestedFromDate (and not the “to” date) to decide periodClipped matches retention semantics and keeps the enforcedWhereClause consistent.

Based on learnings, "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."


413-557: TimeFilter defaults + title callbacks are wired cleanly.

defaultPeriod, maxPeriodDays, and the new submit/history callbacks integrate smoothly with the form state.


603-640: Title generation is gated well to new query results.

The shouldGenerateTitle + historyTitle checks prevent unnecessary regeneration and keep history titles authoritative.

Also applies to: 684-694


812-842: Results callouts provide clear feedback.

Hidden column and period‑limit messaging are concise and actionable.

Also applies to: 988-1033


1035-1093: Chart title loading state and scrollable legend look good.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

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

🤖 Fix all issues with AI agents
In `@internal-packages/tsql/src/query/printer.ts`:
- Around line 1880-1893: getTextColumnForExpression currently returns an
unqualified column name which causes ambiguity in JOINs; update the code that
computes leftTextColumn (used in the left variable) to detect a qualified field
by inspecting node.left.chain and, when an alias/table is present, prepend that
alias to the text column (e.g., alias + "." + textColumn) following the same
pattern used in resolveFieldChainWithTableAlias()/visitField(); ensure you still
call printIdentifier on the fully qualified identifier and fall back to the
existing unqualified behavior when no alias exists.
🧹 Nitpick comments (3)
internal-packages/tsql/src/query/printer.ts (2)

1590-1604: Validation only checks organizationId - consider documenting this intentional design.

The validateRequiredTenantColumns method only validates organizationId and explicitly comments that projectId and environmentId are optional. This aligns with the test suite's "Optional Tenant Filters" tests.

However, if a table defines tenantColumns.projectId but the caller provides only organization_id in enforcedWhereClause, no validation error occurs. This is likely intentional for flexibility, but consider adding a brief JSDoc note explaining why only organizationId is mandatory for tenant isolation.


2463-2480: buildAliasWithoutDataPrefix could match unintended parts.

The method removes the first occurrence of dataPrefix from the parts array using indexOf and splice. If a user has a JSON field path like output.data.data.message where data appears twice, this would only remove the first data, resulting in output_data_message instead of output_message.

This is likely the intended behavior since dataPrefix should only be injected once, but the edge case where user data naturally contains the prefix string could lead to unexpected alias names.

Consider documenting this behavior or using a more targeted removal
 private buildAliasWithoutDataPrefix(
   chain: Array<string | number>,
   dataPrefix: string | null
 ): string {
   // Filter to just string parts and join with underscores
   const parts = chain.filter((p): p is string => typeof p === "string");

   if (dataPrefix) {
-    // Remove the dataPrefix from the parts (it's an implementation detail)
+    // Remove the first occurrence of dataPrefix from the parts (it's an implementation detail)
+    // Note: If user data contains a field named the same as dataPrefix, the alias may differ from expectations
     const prefixIndex = parts.indexOf(dataPrefix);
     if (prefixIndex > 0) {
       // Only remove if it's not the first element (column name)
       parts.splice(prefixIndex, 1);
     }
   }

   return parts.join("_");
 }
internal-packages/tsql/src/query/security.test.ts (1)

668-679: Regex pattern could be more precise for alias extraction.

The pattern /(\w+)\.organization_id/g captures any word character before .organization_id. This works for simple aliases like r and e, but could potentially match unexpected patterns in complex SQL.

Consider a more targeted assertion that explicitly checks the WHERE clause structure.

Minor: More explicit assertion
     // Count organization_id occurrences with different table prefixes
     // This ensures each table gets its own guard, not shared/ambiguous references
-    const orgIdPattern = /(\w+)\.organization_id/g;
+    const orgIdPattern = /\b(\w+)\.`?organization_id`?/g;
     const matches = [...sql.matchAll(orgIdPattern)];
     const tableAliases = matches.map(m => m[1]);
     
     // Should have at least 2 different table aliases for organization_id
     // (one for task_runs alias 'r' and one for task_events alias 'e')
     expect(tableAliases).toContain("r");
     expect(tableAliases).toContain("e");
+    
+    // Verify we have exactly 2 distinct aliases (no duplicates or unexpected matches)
+    const uniqueAliases = new Set(tableAliases);
+    expect(uniqueAliases.size).toBe(2);
📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 32a1ed4 and 700bf72.

📒 Files selected for processing (3)
  • apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query.ai-title.tsx
  • internal-packages/tsql/src/query/printer.ts
  • internal-packages/tsql/src/query/security.test.ts
🧰 Additional context used
📓 Path-based instructions (10)
**/*.{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}: Always import tasks from @trigger.dev/sdk, never use @trigger.dev/sdk/v3 or deprecated client.defineJob pattern
Every Trigger.dev task must be exported and have a unique id property with no timeouts in the run function

Files:

  • apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query.ai-title.tsx
  • internal-packages/tsql/src/query/security.test.ts
  • internal-packages/tsql/src/query/printer.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:

  • apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query.ai-title.tsx
**/*.{ts,tsx,js,jsx}

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

Use function declarations instead of default exports

Import from @trigger.dev/core using subpaths only, never import from root

Files:

  • apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query.ai-title.tsx
  • internal-packages/tsql/src/query/security.test.ts
  • internal-packages/tsql/src/query/printer.ts
apps/webapp/app/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)

Access all environment variables through the env export of env.server.ts instead of directly accessing process.env in the Trigger.dev webapp

Files:

  • apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query.ai-title.tsx
apps/webapp/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)

apps/webapp/**/*.{ts,tsx}: When importing from @trigger.dev/core in the webapp, use subpath exports from the package.json instead of importing from the root path
Follow the Remix 2.1.0 and Express server conventions when updating the main trigger.dev webapp

Access environment variables via env export from apps/webapp/app/env.server.ts, never use process.env directly

Files:

  • apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query.ai-title.tsx
**/*.{js,ts,jsx,tsx,json,md,yaml,yml}

📄 CodeRabbit inference engine (AGENTS.md)

Format code using Prettier before committing

Files:

  • apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query.ai-title.tsx
  • internal-packages/tsql/src/query/security.test.ts
  • internal-packages/tsql/src/query/printer.ts
**/*.{test,spec}.{ts,tsx}

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

Use vitest for all tests in the Trigger.dev repository

Files:

  • internal-packages/tsql/src/query/security.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:

  • internal-packages/tsql/src/query/security.test.ts
  • internal-packages/tsql/src/query/printer.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

**/*.test.{ts,tsx,js,jsx}: Use vitest exclusively for testing and never mock anything - use testcontainers instead
Place test files next to source files with naming pattern: source file (e.g., MyService.ts) → MyService.test.ts

Files:

  • internal-packages/tsql/src/query/security.test.ts
**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • internal-packages/tsql/src/query/security.test.ts
🧠 Learnings (3)
📚 Learning: 2025-12-08T15:19:56.823Z
Learnt from: 0ski
Repo: triggerdotdev/trigger.dev PR: 2760
File: apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam/route.tsx:278-281
Timestamp: 2025-12-08T15:19:56.823Z
Learning: In apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam/route.tsx, the tableState search parameter uses intentional double-encoding: the parameter value contains a URL-encoded URLSearchParams string, so decodeURIComponent(value("tableState") ?? "") is required to fully decode it before parsing with new URLSearchParams(). This pattern allows bundling multiple filter/pagination params as a single search parameter.

Applied to files:

  • apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query.ai-title.tsx
  • internal-packages/tsql/src/query/security.test.ts
📚 Learning: 2025-08-14T10:53:54.526Z
Learnt from: myftija
Repo: triggerdotdev/trigger.dev PR: 2391
File: apps/webapp/app/services/organizationAccessToken.server.ts:50-0
Timestamp: 2025-08-14T10:53:54.526Z
Learning: In the Trigger.dev codebase, token service functions (like revokePersonalAccessToken and revokeOrganizationAccessToken) don't include tenant scoping in their database queries. Instead, authorization and tenant scoping happens at a higher level in the authentication flow (typically in route handlers) before these service functions are called. This is a consistent pattern across both Personal Access Tokens (PATs) and Organization Access Tokens (OATs).

Applied to files:

  • apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query.ai-title.tsx
📚 Learning: 2025-07-21T12:52:44.342Z
Learnt from: ericallam
Repo: triggerdotdev/trigger.dev PR: 2284
File: apps/webapp/app/services/realtimeClient.server.ts:111-127
Timestamp: 2025-07-21T12:52:44.342Z
Learning: Electric (the database service used in the realtimeClient) has built-in SQL injection protection and safely handles whereClause parameters passed via URL parameters, so direct string interpolation of runId values into SQL where clauses is safe when using Electric.

Applied to files:

  • internal-packages/tsql/src/query/security.test.ts
🧬 Code graph analysis (2)
apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query.ai-title.tsx (6)
apps/webapp/app/services/session.server.ts (1)
  • requireUserId (25-35)
apps/webapp/app/utils/pathBuilder.ts (1)
  • EnvironmentParamSchema (26-28)
apps/webapp/app/models/project.server.ts (1)
  • findProjectBySlug (136-147)
apps/webapp/app/models/runtimeEnvironment.server.ts (1)
  • findEnvironmentBySlug (116-145)
apps/webapp/app/env.server.ts (1)
  • env (1320-1320)
apps/webapp/app/v3/services/aiQueryTitleService.server.ts (1)
  • AIQueryTitleService (15-71)
internal-packages/tsql/src/query/security.test.ts (1)
internal-packages/tsql/src/grammar/TSQLParser.ts (2)
  • whereClause (2216-2241)
  • whereClause (8485-8487)
⏰ 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). (7)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (2, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (5, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (3, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (1, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (3, 8)
  • GitHub Check: units / packages / 🧪 Unit Tests: Packages (1, 1)
  • GitHub Check: typecheck / typecheck
🔇 Additional comments (15)
apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query.ai-title.tsx (5)

1-11: LGTM!

Imports are well-organized and follow coding guidelines: @trigger.dev/core/utils uses subpath import, and environment variables are accessed via the env export from ~/env.server.


13-34: LGTM!

Good use of Zod for request validation. The tryCatch wrapper around request.json() properly handles malformed JSON requests, returning a 400 status instead of an unhandled exception.


36-50: LGTM!

Proper authorization chain: findProjectBySlug verifies the user belongs to the organization, and findEnvironmentBySlug scopes the environment to the authenticated project and user.


52-70: LGTM!

Good defensive check for the OpenAI API key at the route level. The configurable model via env.AI_RUN_FILTER_MODEL with a sensible default is a nice pattern. The quote-stripping regex handles the common AI behavior of adding spurious quotes.


80-81: LGTM!

Consistent response structure across success and error cases.

internal-packages/tsql/src/query/printer.ts (7)

117-118: LGTM! GROUP BY context tracking is correctly scoped.

The queryHasGroupBy flag is properly saved before processing, set based on the presence of group_by, and restored after query processing completes. This ensures nested queries don't pollute the parent's GROUP BY state.

Also applies to: 397-400, 553-553


1672-1702: LGTM! Table-qualified guard expressions address the past review concern.

The createConditionExpression method now accepts an optional tableAlias parameter and constructs the field chain as [tableAlias, column] when provided. This ensures guards bind to the correct table in multi-join queries, addressing the previously identified security concern.


1721-1774: LGTM! Enforced guard creation with proper table qualification.

The createEnforcedGuard method correctly:

  1. Builds a set of valid columns from both exposed and tenant columns
  2. Passes tableAlias to createConditionExpression for all guards
  3. Qualifies required filter guards with [tableAlias, filter.column]
  4. Returns null when no guards apply, avoiding unnecessary AND wrappers

This addresses the past review concerns about ambiguous column resolution in multi-table JOINs.


2256-2284: LGTM! Data prefix injection and GROUP BY-aware type hints.

The logic correctly:

  1. Injects dataPrefix into field chains for JSON subfield access
  2. Only adds .:String type hints when queryHasGroupBy is true AND not in a WHERE comparison context
  3. This avoids the issue where .:String returns NULL in non-GROUP BY queries

The isInWhereComparisonContext method properly distinguishes from isInComparisonContext by excluding GROUP BY context.


2371-2396: Text column resolution handles qualified references correctly.

The getTextColumnForField method properly distinguishes between:

  • Unqualified column (chain length 1)
  • Qualified table.column (chain length 2 with table alias)
  • JSON path access column.subfield or table.column.subfield (returns null)

This ensures text column substitution only happens for bare JSON field references, not subfield access.


2438-2456: Potential off-by-one in injectDataPrefix for qualified references.

For a qualified reference like [table, column, subfield], the method correctly inserts dataPrefix at position 2:

[table, column, dataPrefix, subfield]

However, consider this edge case: if chain.length === 3 and the first part is a table alias, but getDataPrefixForField returns non-null, the slicing at line 2450 (chain.slice(2)) would only include the subfield. This appears correct.

But for unqualified [column, subfield], line 2455 does chain.slice(1) which includes [subfield]. This also appears correct: [column, dataPrefix, subfield].

The logic looks sound.


2707-2730: LGTM! Tenant and required filter columns are now resolvable.

The resolveColumnName method now correctly handles:

  1. Tenant columns (organizationId, projectId, environmentId) from tableSchema.tenantColumns
  2. Required filter columns from tableSchema.requiredFilters

These columns are returned as-is since they're already ClickHouse column names, which is correct behavior for the enforced guard system.

internal-packages/tsql/src/query/security.test.ts (3)

55-62: LGTM! Default options correctly migrated to enforcedWhereClause.

The migration from direct tenant ID fields to the structured enforcedWhereClause with { op: "eq", value: ... } format is correct and aligns with the new enforcement mechanism.


593-680: Excellent test coverage for multi-join tenant guard qualification.

The new test suite comprehensively verifies the security fix:

  1. Basic JOIN with qualified guards (r.organization_id, e.organization_id)
  2. LEFT JOIN scenarios
  3. Multi-way JOINs with three table aliases
  4. Verification that guards bind to correct tables via distinct alias matching

The regex patterns like /\br\b[^,]*organization_id/ effectively verify that guards are prefixed with the correct table alias.


417-432: Tests correctly verify optional tenant filter behavior.

The test structure properly validates that:

  • Only organization_id appears in WHERE when project/env are omitted
  • The enforced guard mechanism respects optional fields
  • Partial provisioning works as expected

This aligns with the validateRequiredTenantColumns logic that only mandates organizationId.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Copy link

@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 2 new potential issues.

Open in Devin Review

Copy link

@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 1 new potential issue.

View issue and 17 additional flags in Devin Review.

Open in Devin Review

@matt-aitken matt-aitken marked this pull request as ready for review January 28, 2026 18:36
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: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
internal-packages/tsql/src/query/printer.ts (1)

639-705: Preserve table qualification when substituting text columns in SELECT.
When a user writes r.output (or output AS alias) in a JOIN, the substitution emits output_text without the table qualifier, which can be ambiguous or bind to the wrong table. This drops the user’s explicit qualification.

🛠️ Suggested fix
-        sqlResult = `${this.printIdentifier(textColumn)} AS ${this.printIdentifier(outputName)}`;
+        const textColumnRef =
+          field.chain.length >= 2 &&
+          typeof field.chain[0] === "string" &&
+          this.tableContexts.has(field.chain[0])
+            ? `${this.printIdentifier(field.chain[0])}.${this.printIdentifier(textColumn)}`
+            : this.printIdentifier(textColumn);
+        sqlResult = `${textColumnRef} AS ${this.printIdentifier(outputName)}`;
@@
-          sqlResult = `${this.printIdentifier(textColumn)} AS ${this.printIdentifier(alias.alias)}`;
+          const textColumnRef =
+            innerField.chain.length >= 2 &&
+            typeof innerField.chain[0] === "string" &&
+            this.tableContexts.has(innerField.chain[0])
+              ? `${this.printIdentifier(innerField.chain[0])}.${this.printIdentifier(textColumn)}`
+              : this.printIdentifier(textColumn);
+          sqlResult = `${textColumnRef} AS ${this.printIdentifier(alias.alias)}`;
-        sqlResult = `${this.printIdentifier(columnSchema.textColumn)} AS ${this.printIdentifier(
-          columnName
-        )}`;
+        sqlResult = `${this.printIdentifier(tableAlias)}.${this.printIdentifier(
+          columnSchema.textColumn
+        )} AS ${this.printIdentifier(columnName)}`;

Also applies to: 853-857

📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 10eccd5 and 3c56314.

📒 Files selected for processing (2)
  • internal-packages/tsql/src/query/printer.test.ts
  • internal-packages/tsql/src/query/printer.ts
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{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}: Always import tasks from @trigger.dev/sdk, never use @trigger.dev/sdk/v3 or deprecated client.defineJob pattern
Every Trigger.dev task must be exported and have a unique id property with no timeouts in the run function

Files:

  • internal-packages/tsql/src/query/printer.ts
  • internal-packages/tsql/src/query/printer.test.ts
**/*.{ts,tsx,js,jsx}

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

Use function declarations instead of default exports

Import from @trigger.dev/core using subpaths only, never import from root

Files:

  • internal-packages/tsql/src/query/printer.ts
  • internal-packages/tsql/src/query/printer.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:

  • internal-packages/tsql/src/query/printer.ts
  • internal-packages/tsql/src/query/printer.test.ts
**/*.{js,ts,jsx,tsx,json,md,yaml,yml}

📄 CodeRabbit inference engine (AGENTS.md)

Format code using Prettier before committing

Files:

  • internal-packages/tsql/src/query/printer.ts
  • internal-packages/tsql/src/query/printer.test.ts
**/*.{test,spec}.{ts,tsx}

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

Use vitest for all tests in the Trigger.dev repository

Files:

  • internal-packages/tsql/src/query/printer.test.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

**/*.test.{ts,tsx,js,jsx}: Use vitest exclusively for testing and never mock anything - use testcontainers instead
Place test files next to source files with naming pattern: source file (e.g., MyService.ts) → MyService.test.ts

Files:

  • internal-packages/tsql/src/query/printer.test.ts
**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • internal-packages/tsql/src/query/printer.test.ts
🧬 Code graph analysis (1)
internal-packages/tsql/src/query/printer.test.ts (3)
internal-packages/tsql/src/index.ts (5)
  • createPrinterContext (119-119)
  • TableSchema (113-113)
  • column (81-81)
  • createSchemaRegistry (82-82)
  • PrinterContext (121-121)
internal-packages/tsql/src/query/printer_context.ts (2)
  • createPrinterContext (249-256)
  • PrinterContext (79-214)
internal-packages/tsql/src/query/schema.ts (3)
  • TableSchema (321-339)
  • column (354-366)
  • createSchemaRegistry (371-387)
⏰ 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). (12)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (2, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (7, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (7, 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 (4, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (6, 8)
  • GitHub Check: units / packages / 🧪 Unit Tests: Packages (1, 1)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (1, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (3, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (3, 8)
  • GitHub Check: typecheck / typecheck

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Copy link

@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 1 new potential issue.

View issue and 20 additional flags in Devin Review.

Open in Devin Review

Comment on lines +72 to +77
// If a queryId was provided, update the CustomerQuery record with the title
if (queryId) {
await prisma.customerQuery.update({
where: { id: queryId, organizationId: project.organizationId },
data: { title },
});

Choose a reason for hiding this comment

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

🔴 AI title endpoint allows any org member to overwrite titles of other users’ saved queries by passing arbitrary queryId

The /resources/.../query/ai-title action updates CustomerQuery.title based only on { id: queryId, organizationId }, without ensuring the CustomerQuery being updated belongs to the requesting user (or otherwise that the user is authorized to mutate that specific history entry).

Actual behavior: any authenticated org member who can obtain another query’s id (e.g. via shared logs, screenshots, leaked network payload, etc.) can POST { queryId: "..." } and overwrite its title.

Expected behavior: only the creator (or an admin role) should be able to mutate that query history record, or the endpoint should avoid taking a client-supplied queryId and instead derive the target record server-side.

Click to expand

The update query only scopes by org:

await prisma.customerQuery.update({
  where: { id: queryId, organizationId: project.organizationId },
  data: { title },
});

apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query.ai-title.tsx:72-77

There is no check against userId, projectId, environmentId, or a role/permission check for mutating arbitrary history items.

Recommendation: Scope the update to the calling user (e.g. include userId in the where clause) or enforce an authorization policy (creator-only, or creator/admin). Alternatively, don’t accept queryId from the client: derive the CustomerQuery row to update from the just-executed query context on the server.

Open in Devin Review

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

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.

2 participants