-
-
Notifications
You must be signed in to change notification settings - Fork 947
feat: add reverse replay tracking with "Replayed as" section in Details tab #2832
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
…ls tab - Add replayed_from_friendly_id column to ClickHouse task_runs_v2 table - Create migration 012_add_task_runs_v2_replayed_from.sql - Update replication service to include the new field - Add getRunReplays query to ClickHouse client (optimized with org/project/env filter) - Update SpanPresenter to query replays from ClickHouse - Add "Replayed as" section in run Details tab showing linked replay runs with status The ClickHouse query filters by organization_id, project_id, and environment_id in the correct order to match the primary key for optimal query performance. This enables users to see which runs have been replayed from the original run, addressing the feedback about tracking replay status of failed runs. Slack thread: https://triggerdotdev.slack.com/archives/C045W9WM3E1/p1767609682537389
|
WalkthroughThis pull request adds replay tracking functionality across the data model and user interface. A new Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Pre-merge checks and finishing touches❌ Failed checks (2 warnings)
✅ Passed checks (1 passed)
✨ Finishing touches
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. Comment |
Review CompleteYour review story is ready! Comment !reviewfast on this PR to re-generate the story. |
There was a problem hiding this 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
@apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam.spans.$spanParam/route.tsx:
- Around line 710-743: The replay status is being cast with `as any` for
`TaskRunStatusCombo`; update the `#getRunReplays()` method in
SpanPresenter.server.ts to return Promise<Array<{ friendlyId: string; status:
TaskRunStatus }>> instead of status: string, and convert/validate the ClickHouse
string values to the TaskRunStatus enum before returning so callers (e.g., use
of `replay.status` in TaskRunStatusCombo) no longer need `as any`; locate
`#getRunReplays()` and the `replay.status` usage to implement the type change
and any necessary coercion/validation logic.
🧹 Nitpick comments (1)
apps/webapp/app/presenters/v3/SpanPresenter.server.ts (1)
292-331: Add explicit null check for result before calling.map().The code checks for
errorbut doesn't explicitly verify thatresultis non-null before callingresult.map(). If the ClickHouse client returns[null, null], the.map()call will throw, get caught by the try-catch, and return[]— but the error log will be misleading about the actual failure.🔎 Suggested improvement
if (error) { logger.error("Error fetching run replays from ClickHouse", { error, organizationId, projectId, environmentId, friendlyId, }); return []; } + if (!result) { + logger.error("No result returned from ClickHouse for run replays", { + organizationId, + projectId, + environmentId, + friendlyId, + }); + return []; + } + return result.map((row) => ({ friendlyId: row.friendly_id, status: row.status, }));
📜 Review details
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
apps/webapp/app/presenters/v3/SpanPresenter.server.tsapps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam.spans.$spanParam/route.tsxapps/webapp/app/services/runsReplicationService.server.tsinternal-packages/clickhouse/schema/012_add_task_runs_v2_replayed_from.sqlinternal-packages/clickhouse/src/index.tsinternal-packages/clickhouse/src/taskRuns.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
Files:
apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam.spans.$spanParam/route.tsxinternal-packages/clickhouse/src/taskRuns.tsinternal-packages/clickhouse/src/index.tsapps/webapp/app/services/runsReplicationService.server.tsapps/webapp/app/presenters/v3/SpanPresenter.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/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam.spans.$spanParam/route.tsxapps/webapp/app/services/runsReplicationService.server.tsapps/webapp/app/presenters/v3/SpanPresenter.server.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Use function declarations instead of default exports
Files:
apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam.spans.$spanParam/route.tsxinternal-packages/clickhouse/src/taskRuns.tsinternal-packages/clickhouse/src/index.tsapps/webapp/app/services/runsReplicationService.server.tsapps/webapp/app/presenters/v3/SpanPresenter.server.ts
apps/webapp/app/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)
Access all environment variables through the
envexport ofenv.server.tsinstead of directly accessingprocess.envin the Trigger.dev webapp
Files:
apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam.spans.$spanParam/route.tsxapps/webapp/app/services/runsReplicationService.server.tsapps/webapp/app/presenters/v3/SpanPresenter.server.ts
apps/webapp/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)
apps/webapp/**/*.{ts,tsx}: When importing from@trigger.dev/corein 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
Files:
apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam.spans.$spanParam/route.tsxapps/webapp/app/services/runsReplicationService.server.tsapps/webapp/app/presenters/v3/SpanPresenter.server.ts
**/*.{js,ts,jsx,tsx,json,md,css,scss}
📄 CodeRabbit inference engine (AGENTS.md)
Format code using Prettier
Files:
apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam.spans.$spanParam/route.tsxinternal-packages/clickhouse/src/taskRuns.tsinternal-packages/clickhouse/src/index.tsapps/webapp/app/services/runsReplicationService.server.tsapps/webapp/app/presenters/v3/SpanPresenter.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) andrealtimeClientGlobal.server.ts(configuration) in the webapp
Files:
apps/webapp/app/services/runsReplicationService.server.ts
🧠 Learnings (13)
📚 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.runs.$runParam.spans.$spanParam/route.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/taskRuns.tsinternal-packages/clickhouse/src/index.tsapps/webapp/app/services/runsReplicationService.server.tsapps/webapp/app/presenters/v3/SpanPresenter.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} : Attach metadata to task runs using the metadata option when triggering, and access/update it inside runs using metadata functions
Applied to files:
internal-packages/clickhouse/src/taskRuns.tsapps/webapp/app/presenters/v3/SpanPresenter.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} : Export tasks with unique IDs within the project to enable proper task discovery and execution
Applied to files:
internal-packages/clickhouse/src/taskRuns.ts
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Subscribe to run updates using `runs.subscribeToRun()` for realtime monitoring of task execution
Applied to files:
internal-packages/clickhouse/src/taskRuns.tsapps/webapp/app/presenters/v3/SpanPresenter.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} : Use the `task()` function from `trigger.dev/sdk/v3` to define tasks with id and run properties
Applied to files:
internal-packages/clickhouse/src/taskRuns.tsapps/webapp/app/presenters/v3/SpanPresenter.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/app/v3/presenters/**/*.server.{ts,tsx} : Organize presenters in the webapp following the pattern `app/v3/presenters/*/*.server.ts` to move complex loader code into classes
Applied to files:
apps/webapp/app/presenters/v3/SpanPresenter.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} : Use logger methods (debug, log, info, warn, error) from `trigger.dev/sdk/v3` for structured logging in tasks
Applied to files:
apps/webapp/app/presenters/v3/SpanPresenter.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} : Specify machine resources using the `machine` property with preset options like 'large-1x'
Applied to files:
apps/webapp/app/presenters/v3/SpanPresenter.server.ts
📚 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/app/presenters/v3/SpanPresenter.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} : Use `trigger.dev/sdk/v3` for all imports in Trigger.dev tasks
Applied to files:
apps/webapp/app/presenters/v3/SpanPresenter.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} : Use `.withStreams()` to subscribe to realtime streams from task metadata in addition to run changes
Applied to files:
apps/webapp/app/presenters/v3/SpanPresenter.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 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/app/presenters/v3/SpanPresenter.server.ts
🧬 Code graph analysis (4)
apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam.spans.$spanParam/route.tsx (6)
apps/webapp/app/presenters/v3/SpanPresenter.server.ts (3)
run(661-667)run(669-734)run(736-738)apps/webapp/app/v3/services/completeAttempt.server.ts (1)
run(419-517)apps/webapp/app/components/primitives/Tooltip.tsx (1)
SimpleTooltip(132-132)apps/webapp/app/components/primitives/TextLink.tsx (1)
TextLink(29-94)apps/webapp/app/utils/pathBuilder.ts (1)
v3RunRedirectPath(298-304)apps/webapp/app/components/runs/v3/TaskRunStatus.tsx (1)
TaskRunStatusCombo(96-111)
internal-packages/clickhouse/src/taskRuns.ts (1)
internal-packages/clickhouse/src/client/types.ts (1)
ClickhouseReader(29-135)
internal-packages/clickhouse/src/index.ts (1)
internal-packages/clickhouse/src/taskRuns.ts (1)
getRunReplays(324-346)
apps/webapp/app/presenters/v3/SpanPresenter.server.ts (1)
apps/webapp/app/services/clickhouseInstance.server.ts (1)
clickhouseClient(5-5)
⏰ 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). (23)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (6, 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 (8, 8)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (8, 8)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (7, 8)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (3, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (4, 8)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (4, 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 (3, 8)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (2, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (1, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (2, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (5, 8)
- GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - pnpm)
- GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - npm)
- 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 - pnpm)
- GitHub Check: typecheck / typecheck
- GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (8)
internal-packages/clickhouse/src/taskRuns.ts (2)
48-48: LGTM! Schema extension follows existing patterns.The
replayed_from_friendly_idfield addition is consistent with the schema structure and aligns with the SQL migration default.
310-346: The query filter order already matches the sort key for optimal performance.The task_runs_v2 table's ORDER BY clause is
(organization_id, project_id, environment_id, created_at, run_id), and the query filters by organization_id, project_id, and environment_id in that exact order, which is optimal for ClickHouse query planning. No changes needed.Regarding the hardcoded
LIMIT 10: Consider whether this should remain fixed or become configurable via settings if pagination support is needed, but this appears intentional for the current use case of displaying recent replays in the UI.apps/webapp/app/services/runsReplicationService.server.ts (1)
834-834: LGTM! Replication service correctly propagates the new field.The addition of
replayed_from_friendly_idfollows the established pattern for optional fields in the TaskRunV2 insert payload.internal-packages/clickhouse/schema/012_add_task_runs_v2_replayed_from.sql (1)
1-10: LGTM! Migration correctly adds the new column.The migration properly adds
replayed_from_friendly_idwith a default value and provides a rollback path.internal-packages/clickhouse/src/index.ts (1)
15-15: LGTM! API integration follows established patterns.The
getRunReplaysfunction is correctly imported and exposed through thetaskRunsAPI, following the same pattern as other query functions.Also applies to: 168-168
apps/webapp/app/presenters/v3/SpanPresenter.server.ts (3)
12-12: LGTM!The import is correctly added and follows project conventions for accessing the ClickHouse client singleton.
214-220: LGTM!The replay data is fetched with the correct parameter order (organizationId, projectId, environmentId) to match the ClickHouse primary key for optimal query performance, as noted in the PR objectives.
288-288: LGTM!The
replaysfield is correctly added to the run response object.
| {run.replays && run.replays.length > 0 && ( | ||
| <Property.Item> | ||
| <Property.Label>Replayed as</Property.Label> | ||
| <Property.Value> | ||
| <div className="flex flex-col gap-1"> | ||
| {run.replays.map((replay) => ( | ||
| <SimpleTooltip | ||
| key={replay.friendlyId} | ||
| button={ | ||
| <TextLink | ||
| to={v3RunRedirectPath(organization, project, { | ||
| friendlyId: replay.friendlyId, | ||
| })} | ||
| className="flex items-center gap-1" | ||
| > | ||
| <CopyableText | ||
| value={replay.friendlyId} | ||
| copyValue={replay.friendlyId} | ||
| asChild | ||
| /> | ||
| <TaskRunStatusCombo | ||
| status={replay.status as any} | ||
| className="text-xs" | ||
| /> | ||
| </TextLink> | ||
| } | ||
| content={`Jump to replay run`} | ||
| disableHoverableContent | ||
| /> | ||
| ))} | ||
| </div> | ||
| </Property.Value> | ||
| </Property.Item> | ||
| )} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
# Search for SpanRun type definition
rg "type SpanRun" apps/webapp --type ts -A 20Repository: triggerdotdev/trigger.dev
Length of output: 5469
🏁 Script executed:
# Search for TaskRunStatus type/enum definition
rg "type TaskRunStatus|enum TaskRunStatus|export.*TaskRunStatus" apps/webapp --type ts -B 2 -A 10Repository: triggerdotdev/trigger.dev
Length of output: 24510
🏁 Script executed:
# Check how replays is typed in the SpanPresenter
rg "replays" apps/webapp --type ts -B 3 -A 3Repository: triggerdotdev/trigger.dev
Length of output: 4525
🏁 Script executed:
# Check the TaskRunStatusCombo component to see what type it expects
rg -A 10 "interface.*Props|type.*Props" apps/webapp/app/components/runs/v3/TaskRunStatusCombo.tsx --type tsRepository: triggerdotdev/trigger.dev
Length of output: 166
🏁 Script executed:
# Get the full SpanRun type definition by looking at Result type
rg "type Result" apps/webapp/app/presenters/v3/SpanPresenter.server.ts -B 5 -A 15Repository: triggerdotdev/trigger.dev
Length of output: 820
🏁 Script executed:
# Look at the #getRunReplays method to see what it returns
rg "#getRunReplays|getRunReplays" apps/webapp/app/presenters/v3/SpanPresenter.server.ts -A 30Repository: triggerdotdev/trigger.dev
Length of output: 2125
🏁 Script executed:
# Check what TaskRunStatus type is imported from
rg "import.*TaskRunStatus" apps/webapp/app/components/runs/v3/TaskRunStatus.tsxRepository: triggerdotdev/trigger.dev
Length of output: 128
🏁 Script executed:
# Look for the actual replay object structure in SpanPresenter
rg "friendlyId.*status" apps/webapp/app/presenters/v3/SpanPresenter.server.ts -B 5 -A 5Repository: triggerdotdev/trigger.dev
Length of output: 409
Remove the as any type assertion and properly type the replay status field.
Line 731 uses as any to cast replay.status to satisfy TaskRunStatusCombo, which expects a TaskRunStatus type. The issue stems from the #getRunReplays() method returning status: string instead of status: TaskRunStatus.
Fix this by updating the return type of #getRunReplays() in SpanPresenter.server.ts to:
Promise<Array<{ friendlyId: string; status: TaskRunStatus }>>This ensures type safety without needing the as any cast. The method can validate or coerce the ClickHouse string values to the proper TaskRunStatus type before returning.
🤖 Prompt for AI Agents
In
@apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam.spans.$spanParam/route.tsx
around lines 710-743, The replay status is being cast with `as any` for
`TaskRunStatusCombo`; update the `#getRunReplays()` method in
SpanPresenter.server.ts to return Promise<Array<{ friendlyId: string; status:
TaskRunStatus }>> instead of status: string, and convert/validate the ClickHouse
string values to the TaskRunStatus enum before returning so callers (e.g., use
of `replay.status` in TaskRunStatusCombo) no longer need `as any`; locate
`#getRunReplays()` and the `replay.status` usage to implement the type change
and any necessary coercion/validation logic.
The ClickHouse query filters by organization_id, project_id, and environment_id
in the correct order to match the primary key for optimal query performance.
This enables users to see which runs have been replayed from the original run,
addressing the feedback about tracking replay status of failed runs.
Slack thread: https://triggerdotdev.slack.com/archives/C045W9WM3E1/p1767609682537389