Skip to content

fix: scope DAG detail remote node for SSE - #2291

Merged
yohamta0 merged 14 commits into
mainfrom
fix-dag-detail-sse-polling
Jun 18, 2026
Merged

yohamta0 merged 14 commits into
mainfrom
fix-dag-detail-sse-polling

Conversation

@yohamta0

@yohamta0 yohamta0 commented Jun 17, 2026 •

Copy link
Copy Markdown
Member

Summary

  • add a scoped remote-node context for DAG and DAG-run detail surfaces
  • pass the resolved remote node through DAG detail REST, SSE, log, artifact, action, and fullscreen-link paths
  • keep SWR fallback polling disabled during SSE retry backoff and enable it only after the SSE fallback threshold

Testing

  • cd ui && pnpm test -- src/hooks/tests/useSSE.test.ts src/hooks/tests/SSEManager.test.ts src/contexts/tests/RemoteNodeContext.test.tsx src/features/dags/components/dag-details/tests/DAGDetailsPanel.test.tsx
  • cd ui && pnpm typecheck
  • cd ui && pnpm build
  • git diff --check

Summary by cubic

Scopes the remote node across DAG and DAG‑run detail views and all SSE topics, preserving that scope in navigation and deep links. Tightens sub‑DAG SSE correctness, defers polling until SSE is unhealthy, and ships immutable, content‑hashed Monaco YAML workers.

  • Bug Fixes

    • Preserve remoteNode via ?remoteNode and scoped links across REST, SSE, logs, artifacts, outputs, approvals, incidents, timeline, chat, editor/design, sub‑runs, and DAG CRUD.
    • Keep SWR polling on during SSE connects/retries; pause only when SSE is healthy; updates useExactDAGRuns, useBoundedDAGRunDetails, pagination, and sseFallbackOptions.
    • SSE topics/sub‑DAG correctness: resubscribe after stale mutations; handle pending add/remove while connecting; require DAG name match for latest; hydrate sub‑DAG details; reset details on target change.
    • Avoid YAML worker reloads: content‑hashed Monaco .worker.js; server serves workers with immutable cache headers.
    • Conformance harness timeout increased to 30s with stdout/stderr on timeouts.
  • Refactors

    • Added RemoteNodeContext/useRemoteNode; wrapped DAG/DAG‑run surfaces; pages resolve scope from URL or app bar.
    • Extended useSSE and all DAG/DAG‑run SSE hooks to accept a remote node; added dagRunUrls helpers to keep remote and sub‑DAG context in deep links.
    • Introduced schemaRegistration utilities to dedupe YAML schema registrations and reduce monaco-editor worker/model churn.
    • CI: run UI e2e only when ui/** changes.

Written for commit d7681df. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • New Features
    • Added shared remote-node scoping across DAG pages, run details, logs/outputs, and execution actions, including correct sub-DAG navigation and fullscreen/new-tab URLs.
    • Added URL helpers to preserve remote-node and related DAG/run identifiers in generated links.
  • Bug Fixes
    • Remote-node selection is now consistently trimmed/normalized and applied across requests, real-time updates, downloads, and SSE streams.
  • Tests
    • Expanded coverage for remote-node precedence/normalization, URL construction, run-details matching, and SSE fallback/reconnect behavior.
  • Chores
    • Improved caching and deterministic naming for content-hashed worker assets; refreshed Monaco schema registration and related UI/tests.

@coderabbitai

coderabbitai Bot commented Jun 17, 2026 •

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Introduces RemoteNodeContext with RemoteNodeProvider and useRemoteNode hook to centralize remote-node resolution across all UI components (override → context value → AppBarContext.selectedRemoteNode → 'local'). All components migrate from direct AppBarContext reads to this hook. Page and panel subtrees are wrapped in RemoteNodeProvider. SSE infrastructure is refined: SSEManager.handleDisconnect correctly computes shouldUseFallback and isConnecting state; useSSECacheSync simplifies polling gating to a single shouldPoll flag; and all SSE wrapper hooks gain an optional remoteNode parameter forwarded through the chain. New URL builders (buildDAGRunPageURL, buildDAGPageURL) enable scoped navigation with remote-node context. buildScopedUrl prop support in DAGDetailsContent and DAGHeader preserves remoteNode across tab and breadcrumb navigation. DAG run query matching extends to filter by optional DAG name; polling logic refines fallback suppression thresholds. DAG editor schema registration is extracted into a dedicated module with deterministic fingerprinting, owner-scoped entries, and multi-editor upsert/remove support. Monaco worker bundle output is configured with 16-character content hashes, and backend cache-control logic treats hashed workers as immutable.

Changes

Remote Node Context & SSE Infrastructure

Layer / File(s) Summary
RemoteNodeContext foundation
ui/src/contexts/RemoteNodeContext.tsx, ui/src/contexts/__tests__/RemoteNodeContext.test.tsx
Defines RemoteNodeContext, RemoteNodeProvider (normalizes/trims remoteNode), and useRemoteNode(override?) hook with tested priority: explicit override → provider value → AppBarContext.selectedRemoteNode → 'local'.
URL construction helpers
ui/src/features/dag-runs/lib/dagRunUrls.ts, ui/src/features/dag-runs/lib/__tests__/dagRunUrls.test.ts
New module provides buildDAGRunPageURL and buildDAGPageURL functions to construct remote-scoped URLs with optional sub-DAG/run context and step/tab parameters, including appendQuery helper and comprehensive tests.
SSE manager, cache sync, and hook infrastructure
ui/src/hooks/SSEManager.ts, ui/src/hooks/__tests__/SSEManager.test.ts, ui/src/hooks/useSSECacheSync.ts, ui/src/hooks/useSSE.ts, ui/src/hooks/useDAGSSE.ts, ui/src/hooks/useDAGHistorySSE.ts, ui/src/hooks/useDAGRunLogsSSE.ts, ui/src/hooks/useStepLogSSE.ts, ui/src/hooks/__tests__/useSSE.test.ts
SSEManager.handleDisconnect computes shouldUseFallback from retry count and sets isConnecting = hasTopics && !shouldUseFallback. flushMutation refines stale-mutation staleness checking and re-add logic. useSSECacheSync simplifies polling gating to single shouldPoll flag. useSSE adopts useRemoteNode. All four SSE sub-hooks accept optional remoteNode forwarded to useSSE. Tests cover fallback activation thresholds, stale mutation recovery, and polling behavior during reconnect.
DAG run matching and polling
ui/src/features/dag-runs/hooks/dagRunDetailsRequest.ts, ui/src/features/dag-runs/hooks/__tests__/dagRunDetailsRequest.test.ts, ui/src/features/dag-runs/hooks/useBoundedDAGRunDetails.ts, ui/src/features/dag-runs/hooks/__tests__/useBoundedDAGRunDetails.test.tsx, ui/src/features/dag-runs/hooks/dagRunPagination.ts, ui/src/features/dag-runs/hooks/__tests__/useExactDAGRuns.test.tsx
matchesRequestedDAGRunDetails gains optional requestedName parameter for name-based filtering. useBoundedDAGRunDetails refines shouldUsePollingFallback negated predicate, explicitly clears state on disable/target-change, includes target?.name in match calls. useExactDAGRuns suppresses fallback polling only when isConnected && !shouldUseFallback. Tests verify polling changes based on SSE health state and target changes.
Scoped navigation: buildScopedUrl
ui/src/features/dags/components/dag-details/DAGDetailsContent.tsx, ui/src/features/dags/components/dag-details/DAGHeader.tsx
DAGDetailsContent adds buildScopedUrl prop; all tab navigation routes through scopedUrl callback. DAGHeader adds buildScopedUrl and uses URLSearchParams for breadcrumb navigation with encodeURIComponent encoding and guards against missing identifiers.
Page-level RemoteNodeProvider wiring
ui/src/pages/dags/dag/index.tsx, ui/src/pages/dag-runs/dag-run/index.tsx, ui/src/pages/design/index.tsx
DAGDetails page derives remoteNode from URL param with fallbacks, introduces buildUrl scoped URL function preserving remoteNode/workspace, wraps content in RemoteNodeProvider. DAGRunDetailsPage derives remoteNode from URL param → AppBarContext → 'local' and wraps in RemoteNodeProvider. WorkflowDesignPage reads remoteNode from URL search params with same fallback chain.
Panel wrapping and SSE setup
ui/src/features/dags/components/dag-details/DAGDetailsPanel.tsx, ui/src/features/dags/components/dag-details/DAGDetailsSidePanel.tsx, ui/src/features/dags/components/dag-details/__tests__/DAGDetailsPanel.test.tsx
DAGDetailsPanel and DAGDetailsSidePanel source remoteNode via useRemoteNode, wrap subtrees in RemoteNodeProvider, pass remoteNode to useDAGSSE, use URL builders for fullscreen navigation. Test verifies remoteNode propagation to SSE and fetch query parameters.
DAG run components
ui/src/features/dag-runs/components/common/DAGRunActions.tsx, ui/src/features/dag-runs/components/dag-run-details/DAGRunDetailsModal.tsx, ui/src/features/dag-runs/components/dag-run-details/DAGRunDetailsPanel.tsx, ui/src/features/dag-runs/components/dag-run-details/DAGRunOutputs.tsx, ui/src/features/dag-runs/components/dag-run-details/DAGRunHeader.tsx
DAGRunActions threads remoteNode through all action API requests. DAGRunDetailsModal adjusts matchesRequestedDAGRunDetails with canQuerySubDag, uses buildDAGRunPageURL for fullscreen. DAGRunDetailsPanel sources remoteNode via hook, adjusts match call with isSubDAGRun argument, uses URL builders. DAGRunOutputs and DAGRunHeader adopt useRemoteNode for queries and breadcrumb links.
DAG execution and log components
ui/src/features/dags/components/dag-execution/DAGExecutionHistory.tsx, ui/src/features/dags/components/dag-execution/ExecutionLog.tsx, ui/src/features/dags/components/dag-execution/StepLog.tsx, ui/src/features/dags/components/dag-execution/ParallelExecutionModal.tsx
DAGExecutionHistory sources remoteNode via hook, passes to useDAGHistorySSE, includes in queries and step-status PATCH, uses buildDAGPageURL for sub-DAG navigation. ExecutionLog and StepLog adopt useRemoteNode for SSE log hooks and REST queries with updated dependencies. ParallelExecutionModal sources remoteNode for sub-DAG run query.
DAG editor and spec components
ui/src/features/dags/components/dag-editor/DAGEditButtons.tsx, ui/src/features/dags/components/dag-editor/DAGSpec.tsx, ui/src/features/dags/components/dag-editor/DAGSpecReadOnly.tsx
DAGEditButtons replaces AppBarContext with useRemoteNode, includes in rename/delete queries and redirect URLs. DAGSpec sources remoteNode from hook, passes to useDAGSSE, removes mutateSpec useEffect, introduces useStableLegacyDefinitionHints and useStableCustomActionHints. DAGSpecReadOnly threads remoteNode through spec fetch, edit-retry preview/submit, diff, and save with updated callback dependencies.
DAG tabs and common components
ui/src/features/dags/components/approval/ApprovalTab.tsx, ui/src/features/dags/components/artifacts/ArtifactsTab.tsx, ui/src/features/dags/components/chat-history/StepMessagesTable.tsx, ui/src/features/dags/components/common/DAGActions.tsx, ui/src/features/dags/components/DAGStatus.tsx, ui/src/features/dags/components/dag-details/DAGSettingsTab.tsx, ui/src/features/dags/components/dag-details/IncidentsTab.tsx, ui/src/features/dags/components/dag-details/NotificationsTab.tsx, ui/src/features/dags/components/dag-details/SubDAGRunsList.tsx, ui/src/features/dags/components/dag-details/WebhookTab.tsx, ui/src/features/dags/components/common/InlineLogViewer.tsx, ui/src/features/dags/components/common/LiveSwitch.tsx, ui/src/features/dags/components/visualization/TimelineChart.tsx
All components source remoteNode from useRemoteNode hook instead of AppBarContext. DAGActions threads remoteNode through all affected API requests. DAGStatus includes remoteNode in step-status PATCH and sub-DAG navigation. Tabs, approval, artifacts, and messaging components update queries/mutations and navigation with hook-sourced remoteNode. Cosmetic JSX reformatting accompanies migrations.
DAG editor schema registration extraction
ui/src/features/dags/components/dag-editor/schemaRegistration.ts, ui/src/features/dags/components/dag-editor/__tests__/schemaRegistration.test.ts, ui/src/features/dags/components/dag-editor/DAGEditor.tsx
New module manages JSON schema registrations with deterministic fingerprinting (recursive normalization and stable JSON stringification), owner-scoped entries, multi-editor upsert/remove, and Monaco YAML conversion. DAGEditor refactors to ref-based registration state with conditional removal/upsert on fingerprint changes and cleanup effects. Tests validate fingerprint stability, equal-content deduplication, stale-removal protection, and shared ownership.
Worker asset caching and backend configuration
ui/webpack.common.js, internal/service/frontend/server.go, internal/service/frontend/server_test.go, ui/src/__tests__/webpack.prod.test.ts
Webpack common config specifies [name].[contenthash:16].worker.js filename for Monaco worker bundle. Go backend adds hasContentHashSuffix helper validating 16-character lowercase hex hash and immutable-cache logic for hashed workers. Tests verify cache-control headers and webpack content-hash generation.
Conformance and documentation
conformance/harness/runner.go, specs/003-value-resolution.md
Conformance harness reads DAGU_CONFORMANCE_COMMAND_TIMEOUT env var (30s default) and applies timeout to subprocess context with enhanced failure messages. Spec clarifies target conformance: current behavior covers only implemented specs; "Not implemented" spec rows are target behavior.
E2E test updates
ui/e2e/dag-crud.spec.ts
DAG CRUD E2E tests updated to expect remoteNode=local query parameter in post-rename and post-delete navigation URLs.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • dagucloud/dagu#2010: Both PRs modify ui/src/features/dag-runs/components/common/DAGRunActions.tsx to incorporate remoteNode handling in retry/reschedule request flows.
  • dagucloud/dagu#2012: This PR updates ui/src/features/dags/components/dag-details/DAGHeader.tsx navigation URL logic with remote-node scoping, directly related to the retrieved PR's URL building patterns.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 19.23% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title directly relates to the main change: introducing scoped remote-node context across DAG and DAG-run detail surfaces for SSE operations.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description check ✅ Passed PR description includes summary, changes list, testing steps, and comprehensive cubic summary but lacks explicit checklist completion and related issues reference.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix-dag-detail-sse-polling

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.

@yohamta0

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 17, 2026 •

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

No issues found across 44 files

Re-trigger cubic

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 9

Caution

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

⚠️ Outside diff range comments (13)
ui/src/pages/dag-runs/dag-run/index.tsx (1)

1-5: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add the required GPL header to this TSX source file.

Line 1 starts with imports, but this file is missing the repository-required GPL v3 header.

Suggested patch
+// Copyright (C) 2026 Yota Hamada
+// SPDX-License-Identifier: GPL-3.0-or-later
+
 import React, { useCallback, useContext, useEffect } from 'react';

As per coding guidelines: **/*.{go,ts,tsx,js,jsx}: Add GPL v3 license headers to source files (managed via make addlicense).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui/src/pages/dag-runs/dag-run/index.tsx` around lines 1 - 5, The file is
missing the required GPL v3 license header at the beginning. Add the GPL v3
license header to the top of the file before the import statements (before the
React import and other imports like useParams, AppBarContext, etc.). You can
either manually add the header or use the `make addlicense` command to
automatically apply the required license headers to all source files as per the
repository's coding guidelines.

Source: Coding guidelines

ui/src/features/dags/components/dag-details/DAGHeader.tsx (1)

191-216: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Align breadcrumb render guards with click-handler prerequisites.

Line 191 and Line 214 can still render href values built from missing rootDAGRunId/rootDAGRunName, producing malformed links (e.g., open-in-new-tab via middle click), even though click handlers guard against this path.

Suggested patch
-              {dagRunToDisplay.rootDAGRunId &&
+              {dagRunToDisplay.rootDAGRunId &&
+                dagRunToDisplay.rootDAGRunName &&
                 dagRunToDisplay.rootDAGRunId !== dagRunToDisplay.dagRunId && (
@@
-              {dagRunToDisplay.parentDAGRunName &&
+              {dagRunToDisplay.parentDAGRunName &&
                 dagRunToDisplay.parentDAGRunId &&
+                dagRunToDisplay.rootDAGRunId &&
+                dagRunToDisplay.rootDAGRunName &&
                 dagRunToDisplay.parentDAGRunName !==
                   dagRunToDisplay.rootDAGRunName &&
                 dagRunToDisplay.parentDAGRunName !== dagRunToDisplay.name && (
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui/src/features/dags/components/dag-details/DAGHeader.tsx` around lines 191 -
216, The second breadcrumb link (parentDAGRunName anchor tag) uses rootDAGRunId
and rootDAGRunName in its href URL, but the render guard condition only checks
for parentDAGRunName and parentDAGRunId presence, not the root values. Add
dagRunToDisplay.rootDAGRunId and dagRunToDisplay.rootDAGRunName existence checks
to the conditional guard that wraps the parent DAG run link to ensure all
required properties are present before rendering the href, preventing malformed
URLs when middle-clicking to open in a new tab.
ui/src/features/dags/components/dag-editor/DAGSpecReadOnly.tsx (2)

1-6: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add the required GPLv3 header to this TSX file.

This modified source file is missing the required GPL header at the top.

Proposed fix
+// Copyright (C) 2026 Yota Hamada
+// SPDX-License-Identifier: GPL-3.0-or-later
+
 /**
  * DAGSpecReadOnly component displays a DAG-run specification snapshot.
  * Root DAG-run snapshots can be edited locally and retried as a new run.

As per coding guidelines, **/*.{go,ts,tsx,js,jsx} files must include GPL v3 license headers (managed via make addlicense).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui/src/features/dags/components/dag-editor/DAGSpecReadOnly.tsx` around lines
1 - 6, The DAGSpecReadOnly.tsx file is missing the required GPLv3 license header
that must be present at the top of all TypeScript and TSX source files according
to the project's coding guidelines. Add the GPL v3 license header to the
beginning of the file by running the make addlicense command, which will
automatically prepend the correct license header to this file and any other
source files missing it.

Source: Coding guidelines


344-348: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Preserve remoteNode when navigating to the newly created DAG run.

Line 344 currently drops node scope from the URL, which can route to the wrong node when the current scope came from URL override.

Proposed fix
-      navigate(
-        `/dag-runs/${encodeURIComponent(dagName)}/${encodeURIComponent(
-          retryData.dagRunId
-        )}`
-      );
+      const nextRunPath = `/dag-runs/${encodeURIComponent(dagName)}/${encodeURIComponent(
+        retryData.dagRunId
+      )}`;
+      const nextRunSearch = new URLSearchParams();
+      if (remoteNode !== 'local') {
+        nextRunSearch.set('remoteNode', remoteNode);
+      }
+      const nextRunQuery = nextRunSearch.toString();
+      navigate(nextRunQuery ? `${nextRunPath}?${nextRunQuery}` : nextRunPath);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui/src/features/dags/components/dag-editor/DAGSpecReadOnly.tsx` around lines
344 - 348, The navigate function call to the newly created DAG run does not
preserve the remoteNode scope from the current URL context. Modify the navigate
call to include the remoteNode parameter as a query parameter in the destination
URL, ensuring it is properly encoded using encodeURIComponent. This will
maintain the correct node scope when routing to the DAG run details page,
preventing users from being routed to the wrong node when they had a specific
node selected via URL override.
ui/src/features/dags/components/dag-editor/DAGEditButtons.tsx (1)

1-5: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add the required GPLv3 header to this TSX file.

This modified source file is missing the repository-required GPL header, which creates a licensing compliance gap.

Proposed fix
+// Copyright (C) 2026 Yota Hamada
+// SPDX-License-Identifier: GPL-3.0-or-later
+
 /**
  * DAGEditButtons component provides buttons for renaming and deleting a DAG.
  *

As per coding guidelines, **/*.{go,ts,tsx,js,jsx} files must include GPL v3 license headers (managed via make addlicense).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui/src/features/dags/components/dag-editor/DAGEditButtons.tsx` around lines 1
- 5, The DAGEditButtons.tsx file is missing the required GPLv3 license header
that should appear at the beginning of all source files. Add the GPLv3 license
header comment block at the very top of the file, before the existing JSDoc
comment block that starts with the module documentation. You can use the make
addlicense command to automatically add the proper license headers to TSX files
according to repository standards.

Source: Coding guidelines

ui/src/hooks/useStepLogSSE.ts (1)

1-1: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add the required GPL v3 header to this TypeScript file.

This file is missing the repository-required GPL header.

Suggested patch
+// Copyright (C) 2026 Yota Hamada
+// SPDX-License-Identifier: GPL-3.0-or-later
+
 import { SSEState, useSSE } from './useSSE';

As per coding guidelines, **/*.{go,ts,tsx,js,jsx} must “Add GPL v3 license headers to source files (managed via make addlicense)”.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui/src/hooks/useStepLogSSE.ts` at line 1, The file useStepLogSSE.ts is
missing the required GPL v3 license header that must appear at the beginning of
all TypeScript source files according to the repository guidelines. Add the GPL
v3 license header comment block before the existing import statement at the top
of the file. The repository provides a make command (make addlicense) that can
be used to automatically add or manage these license headers across source
files, which is the recommended approach for maintaining consistency.

Source: Coding guidelines

ui/src/hooks/__tests__/useSSE.test.ts (1)

1-1: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add the required GPL v3 header to this TypeScript test file.

This file is missing the repository-required GPL header.

Suggested patch
+// Copyright (C) 2026 Yota Hamada
+// SPDX-License-Identifier: GPL-3.0-or-later
+
 import { describe, expect, it } from 'vitest';

As per coding guidelines, **/*.{go,ts,tsx,js,jsx} must “Add GPL v3 license headers to source files (managed via make addlicense)”.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui/src/hooks/__tests__/useSSE.test.ts` at line 1, The file useSSE.test.ts is
missing the required GPL v3 license header that must be present at the beginning
of all TypeScript files according to repository guidelines. Add the GPL v3
license header as a comment block at the very top of the file, before the import
statement for describe, expect, and it from vitest. The header should follow the
standard GPL v3 format as defined by the repository's addlicense tool.

Source: Coding guidelines

ui/src/hooks/__tests__/SSEManager.test.ts (1)

1-1: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add the required GPL v3 header to this TypeScript test file.

This file is missing the repository-required GPL header.

Suggested patch
+// Copyright (C) 2026 Yota Hamada
+// SPDX-License-Identifier: GPL-3.0-or-later
+
 import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';

As per coding guidelines, **/*.{go,ts,tsx,js,jsx} must “Add GPL v3 license headers to source files (managed via make addlicense)”.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui/src/hooks/__tests__/SSEManager.test.ts` at line 1, The file
SSEManager.test.ts is missing the required GPL v3 license header. Add the GPL v3
license header comment block at the very beginning of the file, before the
import statement that starts with "import { afterEach, beforeEach, describe,
expect, it, vi } from 'vitest'". The header should follow the standard GPL v3
format used by the make addlicense command in the repository to ensure
consistency with other TypeScript and JavaScript files.

Source: Coding guidelines

ui/src/features/dag-runs/components/common/DAGRunActions.tsx (1)

1-1: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add required GPLv3 headers to modified TSX files.

This and several other touched TSX files in this cohort are missing the required GPL header. Please run make addlicense before merge to satisfy repository license-compliance rules.

As per coding guidelines "**/*.{go,ts,tsx,js,jsx}: Add GPL v3 license headers to source files (managed via make addlicense)."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui/src/features/dag-runs/components/common/DAGRunActions.tsx` at line 1, The
file DAGRunActions.tsx is missing the required GPLv3 license header at the top
of the file. Run the make addlicense command from the repository root to
automatically add the GPL v3 license headers to all modified TSX files including
DAGRunActions.tsx as per the repository's license-compliance requirements.

Source: Coding guidelines

ui/src/features/dags/components/visualization/TimelineChart.tsx (1)

1-12: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add the required GPLv3 file header.

This TSX file is missing the repository’s GPL header.

Suggested fix
+// Copyright (C) 2026 Yota Hamada
+// SPDX-License-Identifier: GPL-3.0-or-later
+
 /**
  * TimelineChart component visualizes the execution timeline of a DAG run.

As per coding guidelines, **/*.{go,ts,tsx,js,jsx}: Add GPL v3 license headers to source files (managed via make addlicense).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui/src/features/dags/components/visualization/TimelineChart.tsx` around lines
1 - 12, The TimelineChart.tsx file is missing the required GPLv3 license header
at the top of the file. Add the GPL v3 license header comment before the
existing JSDoc comment for the TimelineChart component. According to the
repository's guidelines, this can be done by running the make addlicense command
which will automatically add the proper license headers to all source files
matching the pattern **/*.{go,ts,tsx,js,jsx}.

Source: Coding guidelines

ui/src/features/dags/components/DAGStatus.tsx (1)

270-327: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Preserve remoteNode in sub-DAG navigation URLs.

navigateToSubDagRun builds URLs without remoteNode, so sub-run navigation (especially window.open) can resolve to a different node context and show mismatched run data/logs.

💡 Suggested fix
@@
-          url = `/dag-runs/${rootDAGName}/${dagRunId}?${searchParams.toString()}`;
+          if (remoteNode !== 'local') {
+            searchParams.set('remoteNode', remoteNode);
+          }
+          url = `/dag-runs/${rootDAGName}/${dagRunId}?${searchParams.toString()}`;
@@
-          url = `/dags/${fileName}?subDAGRunId=${subDAGRun.dagRunId}&dagRunId=${dagRunId}&step=${node.step.name}&dagRunName=${encodeURIComponent(displayDAGRun.rootDAGRunName || displayDAGRun.name)}`;
+          const params = new URLSearchParams({
+            subDAGRunId: subDAGRun.dagRunId,
+            dagRunId,
+            step: node.step.name,
+            dagRunName: displayDAGRun.rootDAGRunName || displayDAGRun.name,
+          });
+          if (remoteNode !== 'local') {
+            params.set('remoteNode', remoteNode);
+          }
+          url = `/dags/${fileName}?${params.toString()}`;
@@
-    [displayDAGRun, navigate, fileName]
+    [displayDAGRun, navigate, fileName, remoteNode]
   );
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui/src/features/dags/components/DAGStatus.tsx` around lines 270 - 327, The
navigateToSubDagRun function constructs URLs for sub-DAG navigation without
including the remoteNode parameter, which causes the destination to potentially
resolve to a different node context. Add the remoteNode parameter to both URL
construction branches: for the DAG run context, add it to the searchParams
URLSearchParams object, and for the DAG context, include it in the query string
when constructing the `/dags/` URL. Ensure remoteNode is captured from the
appropriate source (such as the current URL or displayDAGRun state) and properly
encoded when added to the URLs.
ui/src/features/dags/components/dag-details/WebhookTab.tsx (1)

1-7: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add the required GPLv3 file header.

This TSX file is missing the standard GPL license header block.

Suggested fix
+// Copyright (C) 2026 Yota Hamada
+// SPDX-License-Identifier: GPL-3.0-or-later
+
 /**
  * WebhookTab component displays webhook configuration for a DAG.

As per coding guidelines, **/*.{go,ts,tsx,js,jsx}: Add GPL v3 license headers to source files (managed via make addlicense).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui/src/features/dags/components/dag-details/WebhookTab.tsx` around lines 1 -
7, The WebhookTab.tsx file is missing the required GPLv3 license header block
that must appear at the very top of all source files. Add the standard GPL v3
license header comment block at the beginning of the file, before the existing
JSDoc module comment. This can be done by running the make addlicense command or
by manually inserting the appropriate license header that matches your project's
standard GPL v3 license format used in other TypeScript and TSX files.

Source: Coding guidelines

ui/src/features/dags/components/dag-details/NodeStatusTableRow.tsx (1)

309-331: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Preserve remoteNode in sub-DAG navigation URLs.

Both sub-DAG navigation branches build new URLs but omit remoteNode, so navigation can fall back to a different node context and show mismatched DAG/DAG-run data.

Suggested fix
       if (isDAGRunContext) {
         // For dagRuns, navigate to /dag-runs/{root-dag-name}/{root-dag-run-id}?subDAGRunId=...
         const searchParams = new URLSearchParams();
         searchParams.set('subDAGRunId', subDAGRunId);
+        searchParams.set('remoteNode', remoteNode);
@@
       } else {
         // For DAGs, use the existing approach with query parameters
         const searchParams = new URLSearchParams();
         searchParams.set('subDAGRunId', subDAGRunId);
+        searchParams.set('remoteNode', remoteNode);

As per coding guidelines, UI requests must remain explicitly scoped by remoteNode in multi-node deployments; these deep links need to carry that scope forward.

Also applies to: 341-360

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui/src/features/dags/components/dag-details/NodeStatusTableRow.tsx` around
lines 309 - 331, The URL construction logic for sub-DAG navigation is missing
the remoteNode parameter in the searchParams, which causes the navigation to
lose multi-node deployment context and potentially display mismatched data. In
both the if branch (when dagRun.rootDAGRunId exists) and the else branch (when
using current dagRun as root), add a searchParams.set call to preserve the
remoteNode value before constructing the final URL using the
searchParams.toString() method. Apply this same fix to the other location
mentioned in the comment.

Source: Coding guidelines

🧹 Nitpick comments (1)
ui/src/hooks/useSSECacheSync.ts (1)

1-1: ⚡ Quick win

Add the required GPL v3 header to this TypeScript file.

Please run make addlicense so this touched file includes the standard license header.

As per coding guidelines, **/*.{go,ts,tsx,js,jsx} must include GPL v3 license headers managed via make addlicense.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui/src/hooks/useSSECacheSync.ts` at line 1, The useSSECacheSync.ts file is
missing the required GPL v3 license header that must be present at the top of
all TypeScript files according to coding guidelines. Add the standard GPL v3
license header to the beginning of this file by running the `make addlicense`
command, which will automatically insert the proper license header and ensure
compliance with the project's licensing requirements for all TypeScript files.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@ui/src/contexts/__tests__/RemoteNodeContext.test.tsx`:
- Line 1: The RemoteNodeContext.test.tsx file is missing the required GPL v3
license header at the beginning of the file. Add the GPL v3 license header to
the top of this TSX file by running the make addlicense command which
automatically manages license headers for source files matching the pattern
*.{go,ts,tsx,js,jsx}. This will ensure the file complies with the coding
guidelines for license headers in source files.

In `@ui/src/contexts/RemoteNodeContext.tsx`:
- Around line 18-31: The code is checking for empty whitespace using trim() for
truthiness validation, but is returning untrimmed values which can propagate
spaces that break downstream operations. In the RemoteNodeProvider function,
modify the value assignment to return the trimmed version of remoteNode instead
of the original value. In the useRemoteNode function, ensure that the returned
value from the override parameter, scopedRemoteNode, and
appBarContext.selectedRemoteNode are all trimmed before being returned to remove
any leading or trailing whitespace.

In `@ui/src/features/dag-runs/components/dag-run-details/DAGRunDetailsModal.tsx`:
- Around line 160-167: The code in the DAGRunDetailsModal component currently
skips setting the remoteNode query parameter when its value is 'local', but this
causes the URL to fall back to the AppBar-selected remote node upon navigation,
breaking scope consistency. Modify the logic where searchParams is constructed
to always include the remoteNode parameter in the query string regardless of its
value, including when it is 'local'. Remove the conditional check on line 161
that currently prevents 'local' from being added to searchParams, ensuring the
explicit node scope is always preserved in the fullscreen URL.

In `@ui/src/features/dag-runs/components/dag-run-details/DAGRunDetailsPanel.tsx`:
- Around line 79-86: The condition checking `if (remoteNode !== 'local')` before
setting the remoteNode parameter should be removed to ensure the remoteNode is
always included in the URL regardless of its value. Currently, when remoteNode
is 'local', it gets omitted from the searchParams, which can cause the node to
resolve differently after navigation when the AppBar has a non-local selection.
Simply remove the conditional check and always call
searchParams.set('remoteNode', remoteNode) to maintain consistent scoped-node
behavior across navigations.

In `@ui/src/features/dags/components/approval/ApprovalTab.tsx`:
- Around line 1-3: The ApprovalTab.tsx file is missing the required GPL v3
license header that should appear at the top of all source files in the
repository. Add the standard GPL v3 license header block at the very beginning
of the file, before the import statements. You can use the command make
addlicense to automatically apply the correct license headers to source files,
or manually add the GPL v3 header comment block that matches the format used in
other TypeScript and TSX files in the repository.

In `@ui/src/features/dags/components/chat-history/StepMessagesTable.tsx`:
- Around line 1-3: The StepMessagesTable.tsx file is missing the required GPL v3
license header that should appear at the very beginning of the file before any
imports. Add the standard GPL v3 license header comment block at the top of the
file before the import statements for ChatMessageRole, Markdown, and
useRemoteNode. You can use the make addlicense command as mentioned in the
coding guidelines to automatically add the license headers to all source files
in the project.

In `@ui/src/features/dags/components/common/InlineLogViewer.tsx`:
- Line 1: The file InlineLogViewer.tsx is missing the required GPL v3 license
header at the top of the file. Run the make addlicense command to automatically
add the GPL v3 license header to this file and any other modified TSX/TS files
in the cohort that are missing it (LiveSwitch.tsx, NodeStatusTableRow.tsx,
SubDAGRunsList.tsx). This will ensure all modified source files comply with the
coding guidelines that require GPL v3 headers for all *.{go,ts,tsx,js,jsx}
files.

In `@ui/src/features/dags/components/dag-details/WebhookTab.tsx`:
- Around line 153-155: The remoteNode value is being concatenated directly into
fetch URLs in query strings without proper URL encoding, which can cause issues
with reserved characters in node names. Apply URL encoding to remoteNode when
building query strings in all fetch calls throughout this file, including in the
getRemoteNodeParam function and at the other locations mentioned (lines 163-165,
214-216, 243-245, 273-274, 309-310). Use the standard encodeURIComponent
function to safely encode the remoteNode variable before it is inserted into any
URL query parameters to prevent query parsing corruption.

In `@ui/src/features/dags/components/dag-execution/ParallelExecutionModal.tsx`:
- Around line 160-170: The setSelectedIndex callbacks in both the ArrowDown and
ArrowUp keyboard event handlers perform modulo arithmetic using
filteredSubRuns.length, which produces NaN when the filtered list is empty
(length equals 0), leaving selectedIndex in an invalid state. Guard against this
by checking if filteredSubRuns.length is greater than 0 before performing the
modulo arithmetic; if the length is 0, set selectedIndex to null instead of
attempting the calculation.

---

Outside diff comments:
In `@ui/src/features/dag-runs/components/common/DAGRunActions.tsx`:
- Line 1: The file DAGRunActions.tsx is missing the required GPLv3 license
header at the top of the file. Run the make addlicense command from the
repository root to automatically add the GPL v3 license headers to all modified
TSX files including DAGRunActions.tsx as per the repository's license-compliance
requirements.

In `@ui/src/features/dags/components/dag-details/DAGHeader.tsx`:
- Around line 191-216: The second breadcrumb link (parentDAGRunName anchor tag)
uses rootDAGRunId and rootDAGRunName in its href URL, but the render guard
condition only checks for parentDAGRunName and parentDAGRunId presence, not the
root values. Add dagRunToDisplay.rootDAGRunId and dagRunToDisplay.rootDAGRunName
existence checks to the conditional guard that wraps the parent DAG run link to
ensure all required properties are present before rendering the href, preventing
malformed URLs when middle-clicking to open in a new tab.

In `@ui/src/features/dags/components/dag-details/NodeStatusTableRow.tsx`:
- Around line 309-331: The URL construction logic for sub-DAG navigation is
missing the remoteNode parameter in the searchParams, which causes the
navigation to lose multi-node deployment context and potentially display
mismatched data. In both the if branch (when dagRun.rootDAGRunId exists) and the
else branch (when using current dagRun as root), add a searchParams.set call to
preserve the remoteNode value before constructing the final URL using the
searchParams.toString() method. Apply this same fix to the other location
mentioned in the comment.

In `@ui/src/features/dags/components/dag-details/WebhookTab.tsx`:
- Around line 1-7: The WebhookTab.tsx file is missing the required GPLv3 license
header block that must appear at the very top of all source files. Add the
standard GPL v3 license header comment block at the beginning of the file,
before the existing JSDoc module comment. This can be done by running the make
addlicense command or by manually inserting the appropriate license header that
matches your project's standard GPL v3 license format used in other TypeScript
and TSX files.

In `@ui/src/features/dags/components/dag-editor/DAGEditButtons.tsx`:
- Around line 1-5: The DAGEditButtons.tsx file is missing the required GPLv3
license header that should appear at the beginning of all source files. Add the
GPLv3 license header comment block at the very top of the file, before the
existing JSDoc comment block that starts with the module documentation. You can
use the make addlicense command to automatically add the proper license headers
to TSX files according to repository standards.

In `@ui/src/features/dags/components/dag-editor/DAGSpecReadOnly.tsx`:
- Around line 1-6: The DAGSpecReadOnly.tsx file is missing the required GPLv3
license header that must be present at the top of all TypeScript and TSX source
files according to the project's coding guidelines. Add the GPL v3 license
header to the beginning of the file by running the make addlicense command,
which will automatically prepend the correct license header to this file and any
other source files missing it.
- Around line 344-348: The navigate function call to the newly created DAG run
does not preserve the remoteNode scope from the current URL context. Modify the
navigate call to include the remoteNode parameter as a query parameter in the
destination URL, ensuring it is properly encoded using encodeURIComponent. This
will maintain the correct node scope when routing to the DAG run details page,
preventing users from being routed to the wrong node when they had a specific
node selected via URL override.

In `@ui/src/features/dags/components/DAGStatus.tsx`:
- Around line 270-327: The navigateToSubDagRun function constructs URLs for
sub-DAG navigation without including the remoteNode parameter, which causes the
destination to potentially resolve to a different node context. Add the
remoteNode parameter to both URL construction branches: for the DAG run context,
add it to the searchParams URLSearchParams object, and for the DAG context,
include it in the query string when constructing the `/dags/` URL. Ensure
remoteNode is captured from the appropriate source (such as the current URL or
displayDAGRun state) and properly encoded when added to the URLs.

In `@ui/src/features/dags/components/visualization/TimelineChart.tsx`:
- Around line 1-12: The TimelineChart.tsx file is missing the required GPLv3
license header at the top of the file. Add the GPL v3 license header comment
before the existing JSDoc comment for the TimelineChart component. According to
the repository's guidelines, this can be done by running the make addlicense
command which will automatically add the proper license headers to all source
files matching the pattern **/*.{go,ts,tsx,js,jsx}.

In `@ui/src/hooks/__tests__/SSEManager.test.ts`:
- Line 1: The file SSEManager.test.ts is missing the required GPL v3 license
header. Add the GPL v3 license header comment block at the very beginning of the
file, before the import statement that starts with "import { afterEach,
beforeEach, describe, expect, it, vi } from 'vitest'". The header should follow
the standard GPL v3 format used by the make addlicense command in the repository
to ensure consistency with other TypeScript and JavaScript files.

In `@ui/src/hooks/__tests__/useSSE.test.ts`:
- Line 1: The file useSSE.test.ts is missing the required GPL v3 license header
that must be present at the beginning of all TypeScript files according to
repository guidelines. Add the GPL v3 license header as a comment block at the
very top of the file, before the import statement for describe, expect, and it
from vitest. The header should follow the standard GPL v3 format as defined by
the repository's addlicense tool.

In `@ui/src/hooks/useStepLogSSE.ts`:
- Line 1: The file useStepLogSSE.ts is missing the required GPL v3 license
header that must appear at the beginning of all TypeScript source files
according to the repository guidelines. Add the GPL v3 license header comment
block before the existing import statement at the top of the file. The
repository provides a make command (make addlicense) that can be used to
automatically add or manage these license headers across source files, which is
the recommended approach for maintaining consistency.

In `@ui/src/pages/dag-runs/dag-run/index.tsx`:
- Around line 1-5: The file is missing the required GPL v3 license header at the
beginning. Add the GPL v3 license header to the top of the file before the
import statements (before the React import and other imports like useParams,
AppBarContext, etc.). You can either manually add the header or use the `make
addlicense` command to automatically apply the required license headers to all
source files as per the repository's coding guidelines.

---

Nitpick comments:
In `@ui/src/hooks/useSSECacheSync.ts`:
- Line 1: The useSSECacheSync.ts file is missing the required GPL v3 license
header that must be present at the top of all TypeScript files according to
coding guidelines. Add the standard GPL v3 license header to the beginning of
this file by running the `make addlicense` command, which will automatically
insert the proper license header and ensure compliance with the project's
licensing requirements for all TypeScript files.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 87ede7a9-1be4-4d66-9a88-37bd0bcc703a

📥 Commits

Reviewing files that changed from the base of the PR and between 6a61c7f and b47839e.

📒 Files selected for processing (44)
  • ui/src/contexts/RemoteNodeContext.tsx
  • ui/src/contexts/__tests__/RemoteNodeContext.test.tsx
  • ui/src/features/dag-runs/components/common/DAGRunActions.tsx
  • ui/src/features/dag-runs/components/dag-run-details/DAGRunDetailsModal.tsx
  • ui/src/features/dag-runs/components/dag-run-details/DAGRunDetailsPanel.tsx
  • ui/src/features/dag-runs/components/dag-run-details/DAGRunOutputs.tsx
  • ui/src/features/dags/components/DAGStatus.tsx
  • ui/src/features/dags/components/approval/ApprovalTab.tsx
  • ui/src/features/dags/components/artifacts/ArtifactsTab.tsx
  • ui/src/features/dags/components/chat-history/StepMessagesTable.tsx
  • ui/src/features/dags/components/common/DAGActions.tsx
  • ui/src/features/dags/components/common/InlineLogViewer.tsx
  • ui/src/features/dags/components/common/LiveSwitch.tsx
  • ui/src/features/dags/components/dag-details/DAGDetailsContent.tsx
  • ui/src/features/dags/components/dag-details/DAGDetailsPanel.tsx
  • ui/src/features/dags/components/dag-details/DAGDetailsSidePanel.tsx
  • ui/src/features/dags/components/dag-details/DAGHeader.tsx
  • ui/src/features/dags/components/dag-details/DAGSettingsTab.tsx
  • ui/src/features/dags/components/dag-details/IncidentsTab.tsx
  • ui/src/features/dags/components/dag-details/NodeStatusTableRow.tsx
  • ui/src/features/dags/components/dag-details/NotificationsTab.tsx
  • ui/src/features/dags/components/dag-details/SubDAGRunsList.tsx
  • ui/src/features/dags/components/dag-details/WebhookTab.tsx
  • ui/src/features/dags/components/dag-details/__tests__/DAGDetailsPanel.test.tsx
  • ui/src/features/dags/components/dag-editor/DAGEditButtons.tsx
  • ui/src/features/dags/components/dag-editor/DAGSpec.tsx
  • ui/src/features/dags/components/dag-editor/DAGSpecReadOnly.tsx
  • ui/src/features/dags/components/dag-execution/DAGExecutionHistory.tsx
  • ui/src/features/dags/components/dag-execution/ExecutionLog.tsx
  • ui/src/features/dags/components/dag-execution/ParallelExecutionModal.tsx
  • ui/src/features/dags/components/dag-execution/StepLog.tsx
  • ui/src/features/dags/components/visualization/TimelineChart.tsx
  • ui/src/hooks/SSEManager.ts
  • ui/src/hooks/__tests__/SSEManager.test.ts
  • ui/src/hooks/__tests__/useSSE.test.ts
  • ui/src/hooks/useDAGHistorySSE.ts
  • ui/src/hooks/useDAGRunLogsSSE.ts
  • ui/src/hooks/useDAGSSE.ts
  • ui/src/hooks/useSSE.ts
  • ui/src/hooks/useSSECacheSync.ts
  • ui/src/hooks/useStepLogSSE.ts
  • ui/src/pages/dag-runs/dag-run/index.tsx
  • ui/src/pages/dags/dag/index.tsx
  • ui/src/pages/design/index.tsx

Comment thread ui/src/contexts/__tests__/RemoteNodeContext.test.tsx
Comment thread ui/src/contexts/RemoteNodeContext.tsx Outdated
Comment thread ui/src/features/dag-runs/components/dag-run-details/DAGRunDetailsModal.tsx Outdated
Comment thread ui/src/features/dag-runs/components/dag-run-details/DAGRunDetailsPanel.tsx Outdated
Comment thread ui/src/features/dags/components/approval/ApprovalTab.tsx
Comment thread ui/src/features/dags/components/chat-history/StepMessagesTable.tsx
Comment thread ui/src/features/dags/components/common/InlineLogViewer.tsx
Comment thread ui/src/features/dags/components/dag-details/WebhookTab.tsx
@yohamta0

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 18, 2026 •

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

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

⚠️ Outside diff range comments (2)
ui/webpack.common.js (1)

1-2: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add the required GPL v3 header to this modified JS source file.

This file is changed in this PR but is missing the mandated license header.

As per coding guidelines: **/*.{go,ts,tsx,js,jsx}: “Add GPL v3 license headers to source files (managed via make addlicense)”.

Suggested patch
+// Copyright (C) 2026 Yota Hamada
+// SPDX-License-Identifier: GPL-3.0-or-later
+
 const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin');
 const path = require('path');
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui/webpack.common.js` around lines 1 - 2, Add the GPL v3 license header to
the beginning of the file before the existing require statements for
MonacoWebpackPlugin and path. The license header should be a comment block
containing the standard GPL v3 text that is mandated for all JavaScript source
files in this project according to the coding guidelines. This can be added
manually or by running the make addlicense command mentioned in the guidelines
to automatically apply the header to modified files.

Source: Coding guidelines

ui/src/hooks/useSSECacheSync.ts (1)

12-18: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Fallback polling is enabled too early during SSE reconnect backoff.

shouldPoll = !sseUsable turns polling on for all disconnected states, including isConnecting=true before fallback threshold. That causes redundant polling during retry backoff and increases request pressure.

Suggested fix
 export function sseFallbackOptions(
   sseResult: SSEState<unknown>,
   fallbackInterval: number = 2000
 ) {
-  const sseUsable = sseResult.isConnected && !sseResult.shouldUseFallback;
-  const shouldPoll = !sseUsable;
+  const shouldPoll =
+    sseResult.shouldUseFallback ||
+    (!sseResult.isConnected && !sseResult.isConnecting);
   return {
     revalidateOnMount: true,
     revalidateIfStale: shouldPoll,
     revalidateOnFocus: shouldPoll,
     refreshInterval: shouldPoll ? fallbackInterval : 0,
   };
 }

Downstream impact: update the connecting-state expectation added in ui/src/hooks/__tests__/useSSE.test.ts accordingly.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui/src/hooks/useSSECacheSync.ts` around lines 12 - 18, The shouldPoll
calculation in useSSECacheSync is too aggressive because using !sseUsable
enables polling during the isConnecting state before the shouldUseFallback
threshold is reached. Instead of shouldPoll = !sseUsable, change it to check
shouldPoll = sseResult.shouldUseFallback so that polling only activates when the
SSE fallback is actually needed, allowing reconnection attempts to complete
without redundant polling. Additionally, update the connecting-state
expectations in the useSSE.test.ts file to reflect that polling should not be
enabled while the system is in a connecting state waiting for the fallback
threshold.
🧹 Nitpick comments (1)
ui/src/features/dag-runs/hooks/__tests__/useBoundedDAGRunDetails.test.tsx (1)

141-168: ⚡ Quick win

Add a sub-DAG name-mismatch regression test for SSE acceptance.

Current additions validate connecting polling, but not the sub-DAG path where name filtering should be bypassed. A focused case here would prevent regressions in matchesRequestedDAGRunDetails wiring.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui/src/features/dag-runs/hooks/__tests__/useBoundedDAGRunDetails.test.tsx`
around lines 141 - 168, Add a new test case to validate the sub-DAG
name-mismatch regression scenario for the useBoundedDAGRunDetails hook. The test
should verify that when handling sub-DAGs, the matchesRequestedDAGRunDetails
function bypasses name filtering logic as expected. Create this test alongside
the existing "keeps polling while the DAG-run SSE topic is still connecting"
test to ensure this filtering bypass behavior does not regress in future
changes.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@ui/src/features/dag-runs/hooks/useBoundedDAGRunDetails.ts`:
- Around line 239-243: The matchesRequestedDAGRunDetails call unconditionally
filters SSE payloads by target name, which causes valid updates to be rejected
in sub-DAG mode where name context differs. Modify the call to conditionally
pass the target?.name parameter only when not operating in sub-DAG mode. Check
the context to determine if the target is a sub-DAG, and if so, pass undefined
or null for the name parameter to matchesRequestedDAGRunDetails instead of
target?.name, allowing SSE updates to be properly processed without stale
details suppression.

In `@ui/src/features/dags/components/DAGStatus.tsx`:
- Line 336: The `onSelectStepOnGraph` callback can retain stale closures with
outdated remoteNode context when a remote-node switch occurs. Locate the
definition of `onSelectStepOnGraph` (likely a useCallback hook) and add
`remoteNode` to its dependency array to ensure the callback is properly
recreated whenever the remoteNode changes, preventing it from using outdated
node context in navigation operations.

---

Outside diff comments:
In `@ui/src/hooks/useSSECacheSync.ts`:
- Around line 12-18: The shouldPoll calculation in useSSECacheSync is too
aggressive because using !sseUsable enables polling during the isConnecting
state before the shouldUseFallback threshold is reached. Instead of shouldPoll =
!sseUsable, change it to check shouldPoll = sseResult.shouldUseFallback so that
polling only activates when the SSE fallback is actually needed, allowing
reconnection attempts to complete without redundant polling. Additionally,
update the connecting-state expectations in the useSSE.test.ts file to reflect
that polling should not be enabled while the system is in a connecting state
waiting for the fallback threshold.

In `@ui/webpack.common.js`:
- Around line 1-2: Add the GPL v3 license header to the beginning of the file
before the existing require statements for MonacoWebpackPlugin and path. The
license header should be a comment block containing the standard GPL v3 text
that is mandated for all JavaScript source files in this project according to
the coding guidelines. This can be added manually or by running the make
addlicense command mentioned in the guidelines to automatically apply the header
to modified files.

---

Nitpick comments:
In `@ui/src/features/dag-runs/hooks/__tests__/useBoundedDAGRunDetails.test.tsx`:
- Around line 141-168: Add a new test case to validate the sub-DAG name-mismatch
regression scenario for the useBoundedDAGRunDetails hook. The test should verify
that when handling sub-DAGs, the matchesRequestedDAGRunDetails function bypasses
name filtering logic as expected. Create this test alongside the existing "keeps
polling while the DAG-run SSE topic is still connecting" test to ensure this
filtering bypass behavior does not regress in future changes.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 15261e25-ca97-45a4-939b-5dddfcbc93d6

📥 Commits

Reviewing files that changed from the base of the PR and between b47839e and 170a0bf.

📒 Files selected for processing (56)
  • internal/service/frontend/server.go
  • internal/service/frontend/server_test.go
  • specs/003-value-resolution.md
  • ui/src/__tests__/webpack.prod.test.ts
  • ui/src/contexts/RemoteNodeContext.tsx
  • ui/src/contexts/__tests__/RemoteNodeContext.test.tsx
  • ui/src/features/dag-runs/components/common/DAGRunActions.tsx
  • ui/src/features/dag-runs/components/dag-run-details/DAGRunDetailsModal.tsx
  • ui/src/features/dag-runs/components/dag-run-details/DAGRunDetailsPanel.tsx
  • ui/src/features/dag-runs/components/dag-run-details/DAGRunHeader.tsx
  • ui/src/features/dag-runs/components/dag-run-details/DAGRunOutputs.tsx
  • ui/src/features/dag-runs/components/dag-run-details/__tests__/DAGRunDetailsPanel.test.tsx
  • ui/src/features/dag-runs/hooks/__tests__/dagRunDetailsRequest.test.ts
  • ui/src/features/dag-runs/hooks/__tests__/useBoundedDAGRunDetails.test.tsx
  • ui/src/features/dag-runs/hooks/__tests__/useExactDAGRuns.test.tsx
  • ui/src/features/dag-runs/hooks/dagRunDetailsRequest.ts
  • ui/src/features/dag-runs/hooks/dagRunPagination.ts
  • ui/src/features/dag-runs/hooks/useBoundedDAGRunDetails.ts
  • ui/src/features/dag-runs/lib/__tests__/dagRunUrls.test.ts
  • ui/src/features/dag-runs/lib/dagRunUrls.ts
  • ui/src/features/dags/components/DAGStatus.tsx
  • ui/src/features/dags/components/approval/ApprovalTab.tsx
  • ui/src/features/dags/components/chat-history/StepMessagesTable.tsx
  • ui/src/features/dags/components/common/InlineLogViewer.tsx
  • ui/src/features/dags/components/common/LiveSwitch.tsx
  • ui/src/features/dags/components/dag-details/DAGDetailsPanel.tsx
  • ui/src/features/dags/components/dag-details/DAGDetailsSidePanel.tsx
  • ui/src/features/dags/components/dag-details/DAGHeader.tsx
  • ui/src/features/dags/components/dag-details/NodeStatusTableRow.tsx
  • ui/src/features/dags/components/dag-details/SubDAGRunsList.tsx
  • ui/src/features/dags/components/dag-details/WebhookTab.tsx
  • ui/src/features/dags/components/dag-editor/DAGEditButtons.tsx
  • ui/src/features/dags/components/dag-editor/DAGEditor.tsx
  • ui/src/features/dags/components/dag-editor/DAGSpec.tsx
  • ui/src/features/dags/components/dag-editor/DAGSpecReadOnly.tsx
  • ui/src/features/dags/components/dag-editor/__tests__/DAGSpecReadOnly.test.tsx
  • ui/src/features/dags/components/dag-editor/__tests__/schemaRegistration.test.ts
  • ui/src/features/dags/components/dag-editor/schemaRegistration.ts
  • ui/src/features/dags/components/dag-execution/DAGExecutionHistory.tsx
  • ui/src/features/dags/components/dag-execution/ExecutionLog.tsx
  • ui/src/features/dags/components/dag-execution/ParallelExecutionModal.tsx
  • ui/src/features/dags/components/dag-execution/StepLog.tsx
  • ui/src/features/dags/components/visualization/TimelineChart.tsx
  • ui/src/hooks/SSEManager.ts
  • ui/src/hooks/__tests__/SSEManager.test.ts
  • ui/src/hooks/__tests__/useSSE.test.ts
  • ui/src/hooks/useDAGHistorySSE.ts
  • ui/src/hooks/useDAGRunLogsSSE.ts
  • ui/src/hooks/useDAGSSE.ts
  • ui/src/hooks/useSSE.ts
  • ui/src/hooks/useSSECacheSync.ts
  • ui/src/hooks/useStepLogSSE.ts
  • ui/src/pages/dag-runs/dag-run/index.tsx
  • ui/src/pages/dags/dag/index.tsx
  • ui/src/pages/design/index.tsx
  • ui/webpack.common.js
✅ Files skipped from review due to trivial changes (1)
  • specs/003-value-resolution.md
🚧 Files skipped from review as they are similar to previous changes (19)
  • ui/src/hooks/useStepLogSSE.ts
  • ui/src/hooks/useDAGRunLogsSSE.ts
  • ui/src/contexts/RemoteNodeContext.tsx
  • ui/src/hooks/useDAGHistorySSE.ts
  • ui/src/hooks/useDAGSSE.ts
  • ui/src/contexts/tests/RemoteNodeContext.test.tsx
  • ui/src/features/dags/components/dag-details/DAGDetailsPanel.tsx
  • ui/src/features/dags/components/chat-history/StepMessagesTable.tsx
  • ui/src/features/dags/components/dag-details/SubDAGRunsList.tsx
  • ui/src/features/dags/components/dag-execution/ExecutionLog.tsx
  • ui/src/features/dags/components/visualization/TimelineChart.tsx
  • ui/src/features/dags/components/common/InlineLogViewer.tsx
  • ui/src/features/dags/components/dag-details/DAGHeader.tsx
  • ui/src/features/dag-runs/components/dag-run-details/DAGRunOutputs.tsx
  • ui/src/features/dags/components/approval/ApprovalTab.tsx
  • ui/src/features/dags/components/dag-execution/DAGExecutionHistory.tsx
  • ui/src/features/dag-runs/components/common/DAGRunActions.tsx
  • ui/src/features/dags/components/dag-details/DAGDetailsSidePanel.tsx
  • ui/src/features/dags/components/dag-editor/DAGSpecReadOnly.tsx

Comment thread ui/src/features/dag-runs/hooks/useBoundedDAGRunDetails.ts
Comment thread ui/src/features/dags/components/DAGStatus.tsx
@yohamta0

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 18, 2026 •

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@yohamta0

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 18, 2026 •

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@ui/src/features/dag-runs/hooks/__tests__/useBoundedDAGRunDetails.test.tsx`:
- Around line 286-323: The test assertion passes regardless of whether SSE
hydration is actually being used because both the fetchDAGRunDetailsMock and
subDAGRunSSEState.current are returning identical payloads. To make the SSE
hydration path verifiable independently, modify the fetchDAGRunDetailsMock to
return different data (such as a different dagRunId or name value) while keeping
subDAGRunSSEState.current with the expected values that should be returned by
the useBoundedDAGRunDetails hook. This way, the expect statement will only pass
if the hook is truly using the SSE hydration data and not just the fetch result.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e8829835-ca8c-459d-9d06-623d47d5eec5

📥 Commits

Reviewing files that changed from the base of the PR and between 170a0bf and 9f79c78.

📒 Files selected for processing (6)
  • ui/src/features/dag-runs/hooks/__tests__/useBoundedDAGRunDetails.test.tsx
  • ui/src/features/dag-runs/hooks/useBoundedDAGRunDetails.ts
  • ui/src/features/dags/components/DAGStatus.tsx
  • ui/src/hooks/__tests__/useSSE.test.ts
  • ui/src/hooks/useSSECacheSync.ts
  • ui/webpack.common.js
🚧 Files skipped from review as they are similar to previous changes (3)
  • ui/webpack.common.js
  • ui/src/hooks/useSSECacheSync.ts
  • ui/src/features/dags/components/DAGStatus.tsx

@yohamta0

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 18, 2026 •

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@yohamta0

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 18, 2026 •

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@yohamta0

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 18, 2026 •

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@ui/e2e/dag-crud.spec.ts`:
- Around line 79-81: The `newName` variable is being directly interpolated into
the RegExp constructor on line 80 without escaping special regex characters. If
the DAG name contains regex metacharacters like `.`, `+`, `*`, or `?`, the
assertion will fail or match unintended URLs. Escape the `newName` string using
a regex escape function (or by replacing special regex characters with their
escaped versions) before constructing the RegExp pattern in the toHaveURL
assertion, so that literal characters in the DAG name are treated as literals
rather than regex syntax.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: cb42cde0-4aae-4f8c-813b-8cb82223f9c8

📥 Commits

Reviewing files that changed from the base of the PR and between 7651469 and 6abb9c6.

📒 Files selected for processing (1)
  • ui/e2e/dag-crud.spec.ts

Comment thread ui/e2e/dag-crud.spec.ts
@yohamta0

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 18, 2026 •

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@cubic-dev-ai

cubic-dev-ai Bot commented Jun 18, 2026

Copy link
Copy Markdown

You're iterating quickly on this pull request. To help protect your rate limits, cubic has paused automatic reviews on new pushes for now—when you're ready for another review, comment @cubic-dev-ai review.

@yohamta0
yohamta0 merged commit bbd1673 into main Jun 18, 2026
13 checks passed
@yohamta0
yohamta0 deleted the fix-dag-detail-sse-polling branch June 18, 2026 09:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant