Skip to content

feat: misc changes for quicker build and deploy times#236

Merged
HardMax71 merged 21 commits intomainfrom
feat/lower-img-sizes
Feb 27, 2026
Merged

feat: misc changes for quicker build and deploy times#236
HardMax71 merged 21 commits intomainfrom
feat/lower-img-sizes

Conversation

@HardMax71
Copy link
Copy Markdown
Owner

@HardMax71 HardMax71 commented Feb 25, 2026


Summary by cubic

Speeds up builds and deploys with Docker layer caching and a slimmer multi‑stage backend; production builds drop source maps. Adds SSE replay status streaming with text/event-stream OpenAPI, admin Svelte stores with auto‑refresh, execution_id filtering for sagas, and faster tests via Redis pub/sub and tighter Kafka/SSE timeouts.

  • Refactors

    • Backend base uses a builder stage with cached uv sync and bytecode compile; runtime drops gcc; backend/.dockerignore prunes tests/docs/secrets; removed the test runner image.
    • CI/Workflows: docker/build-push-action@v6 with GHA layer cache; K3s readiness via kubectl wait; pre‑pull runtime images; uv sync uses lint/test groups with --no-dev; deploy syncs test group before pytest.
    • Replay: status streams via SSE; Redis bus adds a replay channel; SSE service publishes DomainReplaySSEPayload and closes on terminal states; OpenAPI advertises text/event-stream via an EventSourceResponse subclass; replay container registers the SSE provider.
    • Saga list supports execution_id with access checks.
    • Frontend: Admin pages use dedicated Svelte stores (filters, pagination, auto‑refresh); Vitest threads + fake timers with jsdom/node split, deps optimizer, and global cleanup; production builds disable sourcemaps.
    • Tests: E2E waiters switched to Redis pub/sub; reduced flakiness with shorter Kafka timeouts and a smaller SSE consumer pool in test config.
  • Dependencies

    • Frontend: build tooling moved to devDependencies; removed @babel/runtime.
    • Backend: added uv dependency groups (lint/test) and CI uses --group with --no-dev; removed unused instrumentation/deps; pinned async-asgi-testclient; pruned uv.lock.

Written for commit 162b9a3. Summary will update on new commits.

Summary by CodeRabbit

  • Chores

    • Switched backend to a multi-stage, cache-friendly build, expanded image build ignores, removed the dedicated test image, and moved frontend build tooling to dev-only; minor CI workflow formatting change.
  • Tests

    • Centralized and simplified frontend test utilities, unified user interaction helpers, improved timer handling, and updated test setup/spies for toast and meta behaviors.
  • Documentation

    • Updated CI/CD and frontend build docs to reflect new build, caching, and sourcemap behavior.

Copilot AI review requested due to automatic review settings February 25, 2026 19:12
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Feb 25, 2026

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

Switches backend to a BuildKit multi-stage Docker build, reformats CI docker invocation, expands backend build-context ignores, removes test Dockerfile, trims backend deps, moves frontend build tooling to devDependencies and disables prod sourcemaps, and centralizes frontend test user-event helpers used across many tests.

Changes

Cohort / File(s) Summary
CI Workflow
\.github/workflows/stack-tests.yml
Reformatted docker build invocation to shell multiline; CI now documents/use docker/build-push-action@v6 layer caching and concurrent image push flow.
Backend Docker & Context
backend/Dockerfile.base, backend/Dockerfile.test (removed), backend/.dockerignore
Introduces BuildKit multi-stage builder→runtime in Dockerfile.base (build deps, uv cache/mounts, copy venv), removes Dockerfile.test, and expands .dockerignore to exclude tests/docs/secrets/test configs and whitelist file.
Backend deps
backend/pyproject.toml
Removed opentelemetry-asgi/redis and tiktoken; adjusted async-asgi-testclient dev version.
Frontend build config & deps
frontend/package.json, frontend/rollup.config.js, docs/architecture/frontend-build.md
Moved Rollup/Svelte/PostCSS build tooling into devDependencies; made sourcemap/TypeScript sourceMap conditional on !production (disabled in prod); docs updated accordingly.
Frontend tests — shared utils
frontend/src/__tests__/test-utils.ts, frontend/src/**/__tests__/*.test.ts
Adds exported UserEventInstance, user, and userWithTimers helpers; updates many tests to import and reuse these helpers instead of calling userEvent.setup() per test and removes several legacy mock factories.
Frontend test runner config
frontend/vitest.config.ts, frontend/vitest.setup.ts
Adds thread pool and environment mapping, disables CSS in tests, and guards Element.prototype.animate assignment to avoid Node environments.
Docs / CICD
docs/operations/cicd.md
Updates image count, expands caching strategy description to reference GHA layer cache (scope/mode) and describes multi-image push concurrency and error handling.

Sequence Diagram(s)

sequenceDiagram
  participant GHA as GitHub Actions (CI)
  participant Build as Docker BuildKit
  participant Repo as Repository
  participant Registry as GHCR

  GHA->>Build: trigger docker/build-push-action@v6 (build-contexts, cache)
  Build->>Repo: read `backend/Dockerfile.base` (builder + runtime stages)
  Build->>Build: run builder stage (install build deps, uv sync with cache)
  Build->>Build: assemble runtime stage (copy venv/uv, install runtime libs)
  Build->>Registry: push images (concurrent pushes, PID tracking)
  Registry-->>GHA: return push results (success/failure)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰 I hopped through layers, light and spry,
Builder stitched venvs while clouds went by.
Sourcemaps nap in production's den,
Tests now share a friendly hand.
CI hums, images drift to the glen.

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 10.53% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title is vague and generic, using the non-descriptive phrase 'misc changes' which does not convey specific information about the changeset despite the PR making significant infrastructure improvements. Consider a more specific title such as 'feat: optimize builds with multi-stage Docker base image and disabled production sourcemaps' or 'feat: reduce image sizes and build times via Docker optimization and frontend config updates'.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/lower-img-sizes

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

❤️ Share

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

Copy link
Copy Markdown

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

Choose a reason for hiding this comment

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

No issues found across 11 files

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
backend/Dockerfile.base (1)

35-40: Avoid apt-get upgrade in the runtime image build step.

Line 35 makes builds slower and less reproducible. Prefer refreshed base images plus explicit package installs only.

Suggested diff
-RUN apt-get update && apt-get upgrade -y \
+RUN apt-get update \
     && apt-get install -y --no-install-recommends \
     curl \
     libsnappy1v5 \
     liblzma5 \
     && rm -rf /var/lib/apt/lists/*
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/Dockerfile.base` around lines 35 - 40, Remove the apt-get upgrade
step in the Dockerfile RUN line to avoid slow, non-reproducible builds: change
the RUN command that currently contains "apt-get update && apt-get upgrade -y \
..." to only run "apt-get update && apt-get install -y --no-install-recommends
curl libsnappy1v5 liblzma5 && rm -rf /var/lib/apt/lists/*" so the image relies
on the refreshed base image plus explicit package installs (preserve
--no-install-recommends and the cleanup at the end).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@backend/Dockerfile.base`:
- Around line 35-40: Remove the apt-get upgrade step in the Dockerfile RUN line
to avoid slow, non-reproducible builds: change the RUN command that currently
contains "apt-get update && apt-get upgrade -y \ ..." to only run "apt-get
update && apt-get install -y --no-install-recommends curl libsnappy1v5 liblzma5
&& rm -rf /var/lib/apt/lists/*" so the image relies on the refreshed base image
plus explicit package installs (preserve --no-install-recommends and the cleanup
at the end).

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d8ac4cc and ea55011.

⛔ Files ignored due to path filters (2)
  • backend/uv.lock is excluded by !**/*.lock
  • frontend/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (9)
  • .github/workflows/stack-tests.yml
  • backend/.dockerignore
  • backend/Dockerfile.base
  • backend/Dockerfile.test
  • backend/pyproject.toml
  • docs/architecture/frontend-build.md
  • docs/operations/cicd.md
  • frontend/package.json
  • frontend/rollup.config.js
💤 Files with no reviewable changes (2)
  • backend/Dockerfile.test
  • backend/pyproject.toml

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This pull request optimizes build and deploy times through several changes: disabling sourcemaps in production builds, moving frontend build tools to devDependencies, removing unused backend dependencies, implementing multi-stage Docker builds for the backend base image, and adding GHA layer caching for the backend image. However, there is a critical issue where the async-asgi-testclient dependency was removed but is still actively used in SSE endpoint tests.

Changes:

  • Frontend: Disabled sourcemaps in production to reduce bundle size and build time
  • Backend: Removed unused dependencies (tiktoken, opentelemetry-instrumentation-asgi, opentelemetry-instrumentation-redis) and the test dependency async-asgi-testclient
  • Docker: Implemented multi-stage build for Dockerfile.base to separate build-time and runtime dependencies, removed Dockerfile.test, enhanced .dockerignore
  • CI/CD: Added GHA layer caching for backend image builds, updated documentation to reflect 4 images instead of 5

Reviewed changes

Copilot reviewed 9 out of 11 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
frontend/rollup.config.js Conditionally disable sourcemaps in production (!production)
frontend/package.json Move build tools (rollup, plugins, postcss, etc.) from dependencies to devDependencies
frontend/package-lock.json Update dev markers for moved dependencies
backend/pyproject.toml Remove unused dependencies: tiktoken, opentelemetry-instrumentation-asgi, opentelemetry-instrumentation-redis, async-asgi-testclient
backend/uv.lock Reflect dependency removals in lock file
backend/Dockerfile.base Implement multi-stage build with separate builder and runtime stages
backend/Dockerfile.test Remove unused test dockerfile
backend/.dockerignore Add exclusions for tests, docs, configs to reduce build context
.github/workflows/stack-tests.yml Add GHA layer caching for backend image with scope=backend, mode=max
docs/operations/cicd.md Update to 4 images (was 5), document GHA caching strategy
docs/architecture/frontend-build.md Clarify that sourcemaps are only in development builds
Files not reviewed (1)
  • frontend/package-lock.json: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread frontend/rollup.config.js
Comment thread backend/pyproject.toml Outdated
@HardMax71 HardMax71 changed the title feat: misc changes for quicker build and dpeloy times feat: misc changes for quicker build and deploy times Feb 25, 2026
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

Caution

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

⚠️ Outside diff range comments (7)
frontend/src/routes/__tests__/Settings.test.ts (1)

80-80: ⚠️ Potential issue | 🟡 Minor

afterEach is missing cleanup().

The afterEach already calls vi.unstubAllGlobals(), but cleanup() is absent, leaving rendered components mounted between tests.

🛠️ Proposed fix
-import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
-import { render, screen, waitFor } from '@testing-library/svelte';
+import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
+import { render, screen, waitFor, cleanup } from '@testing-library/svelte';
 ...
-  afterEach(() => vi.unstubAllGlobals());
+  afterEach(() => {
+    vi.unstubAllGlobals();
+    cleanup();
+  });

Based on learnings: "call cleanup() in afterEach and vi.clearAllMocks() in beforeEach."

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

In `@frontend/src/routes/__tests__/Settings.test.ts` at line 80, The test teardown
is incomplete: ensure rendered components are unmounted by calling cleanup() in
the afterEach block and reset mocks at test start by calling vi.clearAllMocks()
in beforeEach; update the test file to call cleanup() alongside
vi.unstubAllGlobals() in the existing afterEach and add a beforeEach that
invokes vi.clearAllMocks() so tests don't leak DOM or mock state (refer to
afterEach, beforeEach, vi.unstubAllGlobals, cleanup, vi.clearAllMocks).
frontend/src/components/editor/__tests__/ResourceLimits.test.ts (1)

1-9: ⚠️ Potential issue | 🟡 Minor

Missing both beforeEach(() => vi.clearAllMocks()) and afterEach(() => cleanup()).

Unlike the other migrated test files, ResourceLimits.test.ts has no beforeEach or afterEach hooks at all, violating both halves of the guideline.

🛠️ Proposed fix
-import { describe, it, expect, beforeEach, vi } from 'vitest';
-import { render, screen } from '@testing-library/svelte';
+import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
+import { render, screen, cleanup } from '@testing-library/svelte';
 import { user } from '$test/test-utils';
 ...
 describe('ResourceLimits', () => {
+  beforeEach(() => {
+    vi.clearAllMocks();
+  });
+  afterEach(() => {
+    cleanup();
+  });
+
   it('renders nothing when limits is null', ...

Based on learnings: "call cleanup() in afterEach and vi.clearAllMocks() in beforeEach."

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

In `@frontend/src/components/editor/__tests__/ResourceLimits.test.ts` around lines
1 - 9, Add the missing test setup/teardown: import cleanup from
'@testing-library/svelte' and add a beforeEach hook that calls
vi.clearAllMocks() and an afterEach hook that calls cleanup(); place these near
the top of ResourceLimits.test.ts so the suite resets mocks and DOM between
tests (referencing beforeEach, afterEach, vi.clearAllMocks, and cleanup to
locate where to add them).
frontend/src/components/editor/__tests__/LanguageSelect.test.ts (1)

1-28: 🛠️ Refactor suggestion | 🟠 Major

Add beforeEach/afterEach with vi.clearAllMocks() and cleanup().

This suite has no beforeEach or afterEach, violating the guideline requiring vi.clearAllMocks() in beforeEach and cleanup() in afterEach. Without cleanup the DOM accumulates rendered LanguageSelect components across tests. As per coding guidelines, both hooks are mandatory.

🛠️ Proposed fix
-import { describe, it, expect, beforeEach, vi } from 'vitest';
-import { render, screen, within, fireEvent, waitFor } from '@testing-library/svelte';
+import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
+import { render, screen, within, fireEvent, waitFor, cleanup } from '@testing-library/svelte';
 import { user } from '$test/test-utils';
 describe('LanguageSelect', () => {
+  beforeEach(() => {
+    vi.clearAllMocks();
+  });
+
+  afterEach(() => {
+    cleanup();
+  });
+
   async function openMenu() {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/components/editor/__tests__/LanguageSelect.test.ts` around lines
1 - 28, Add test lifecycle hooks to this test file: import cleanup from
'@testing-library/svelte' at the top, then add a beforeEach that calls
vi.clearAllMocks() and an afterEach that calls cleanup(); place these hooks at
the top-level of the suite (e.g., inside the describe('LanguageSelect', ...)
block or file-level) so they run around tests that use renderSelect and
openMenu, ensuring mocks are reset and the DOM is cleaned between tests.
frontend/src/components/admin/events/__tests__/EventDetailsModal.test.ts (1)

25-28: 🛠️ Refactor suggestion | 🟠 Major

Add afterEach with cleanup().

beforeEach clears mocks correctly, but there is no afterEach to unmount rendered components. As per coding guidelines, cleanup() must be called in afterEach.

🛠️ Proposed fix
-import { describe, it, expect, beforeEach, vi } from 'vitest';
-import { render, screen } from '@testing-library/svelte';
+import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
+import { render, screen, cleanup } from '@testing-library/svelte';
   beforeEach(() => {
     vi.clearAllMocks();
   });
+
+  afterEach(() => {
+    cleanup();
+  });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/components/admin/events/__tests__/EventDetailsModal.test.ts`
around lines 25 - 28, The test suite for EventDetailsModal currently only clears
mocks in beforeEach but never unmounts rendered components; add an afterEach
hook that calls cleanup() to unmount and clean up DOM between tests (e.g., add
afterEach(() => { cleanup(); }) alongside the existing beforeEach that calls
vi.clearAllMocks()) so rendered components are properly torn down after each
test.
frontend/src/routes/__tests__/Notifications.test.ts (1)

1-43: 🛠️ Refactor suggestion | 🟠 Major

Add afterEach with cleanup().

There is no afterEach in this suite. Without cleanup(), each render() call accumulates DOM nodes across tests, causing cross-test bleed. As per coding guidelines, cleanup() must be called in afterEach.

🛠️ Proposed fix
-import { describe, it, expect, beforeEach, vi } from 'vitest';
+import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
 import { render, screen, waitFor } from '@testing-library/svelte';
+import { cleanup } from '@testing-library/svelte';
 import { createMockNotification, createMockNotifications, user } from '$test/test-utils';
   beforeEach(() => {
     vi.clearAllMocks();
     ...
   });
+
+  afterEach(() => {
+    cleanup();
+  });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/routes/__tests__/Notifications.test.ts` around lines 1 - 43, The
test suite is missing cleanup() after each test which causes DOM nodes to
accumulate; import cleanup from '@testing-library/svelte' at the top alongside
render/screen/waitFor and add an afterEach(() => cleanup()) block (keeping the
existing beforeEach and vi.clearAllMocks) so each test's DOM is torn down;
reference the test file Notifications.test.ts and its beforeEach and render
usages to locate where to add the import and the afterEach call.
frontend/src/components/__tests__/NotificationCenter.test.ts (1)

152-172: 🛠️ Refactor suggestion | 🟠 Major

beforeEach should call vi.clearAllMocks() and afterEach should call cleanup().

Two guideline violations:

  1. beforeEach uses individual .mockReset() calls but does not call vi.clearAllMocks(). vi.restoreAllMocks() in afterEach restores spies, but mock state set up between beforeEach and the test's own mocks won't be reliably cleared without vi.clearAllMocks() in beforeEach.
  2. afterEach calls vi.restoreAllMocks() but never calls cleanup(), leaving rendered NotificationCenter instances mounted in the DOM.

As per coding guidelines, both hooks are required.

🛠️ Proposed fix
-import { render, screen, waitFor } from '@testing-library/svelte';
+import { render, screen, waitFor, cleanup } from '@testing-library/svelte';
   beforeEach(() => {
+    vi.clearAllMocks();
     mocks.mockAuthStore.isAuthenticated = true;
     ...
   });

-  afterEach(() => { vi.restoreAllMocks(); });
+  afterEach(() => {
+    cleanup();
+    vi.restoreAllMocks();
+  });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/components/__tests__/NotificationCenter.test.ts` around lines
152 - 172, The test setup should clear all mock state at the start and unmount
rendered components at the end: in the beforeEach block (where
mocks.mockAuthStore and others are initialized and many .mockReset() calls
occur) add a call to vi.clearAllMocks() to ensure mock histories are cleared
before each test, and in the afterEach block (which currently calls
vi.restoreAllMocks()) add a call to cleanup() to unmount any rendered
NotificationCenter instances; keep existing vi.restoreAllMocks() and console spy
handling intact.
frontend/src/components/__tests__/Header.test.ts (1)

60-79: 🛠️ Refactor suggestion | 🟠 Major

beforeEach should call vi.clearAllMocks() and afterEach should call cleanup().

Two guideline violations:

  1. beforeEach individually calls .mockReset() on select mocks but doesn't call vi.clearAllMocks(), which would also reset any spies created elsewhere in the suite.
  2. afterEach only restores window.innerWidth but never calls cleanup(), leaving mounted Header components in the DOM between tests.

As per coding guidelines, both vi.clearAllMocks() in beforeEach and cleanup() in afterEach are required.

🛠️ Proposed fix
-import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
-import { render, screen, waitFor } from '@testing-library/svelte';
+import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
+import { render, screen, waitFor, cleanup } from '@testing-library/svelte';
   beforeEach(() => {
+    vi.clearAllMocks();
     setAuth(false);
     mocks.mockThemeStore.value = 'auto';
-    mocks.mockAuthStore.logout.mockReset();
-    mocks.mockToggleTheme.mockReset();
-    mocks.mockGoto.mockReset();
     originalInnerWidth = window.innerWidth;
     ...
   });

   afterEach(() => {
     Object.defineProperty(window, 'innerWidth', { writable: true, configurable: true, value: originalInnerWidth });
+    cleanup();
   });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/components/__tests__/Header.test.ts` around lines 60 - 79, Add
vi.clearAllMocks() at the start of the beforeEach block and call cleanup() in
afterEach so all mocks/spies and mounted components are fully reset between
tests; update the existing beforeEach that currently calls
mocks.mockAuthStore.logout.mockReset() and others to also invoke
vi.clearAllMocks(), and add cleanup() alongside restoring window.innerWidth in
the afterEach that currently only resets originalInnerWidth.
♻️ Duplicate comments (4)
frontend/src/components/admin/events/__tests__/EventFilters.test.ts (1)

1-3: Missing cleanup() in afterEach.

Same guideline violation as noted in ReplayPreviewModal.test.ts — please add cleanup() to an afterEach block here as well.

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

In `@frontend/src/components/admin/events/__tests__/EventFilters.test.ts` around
lines 1 - 3, The test file EventFilters.test.ts is missing an explicit cleanup
call after each test; import cleanup from '@testing-library/svelte' and add an
afterEach(() => cleanup()) alongside the existing beforeEach so the DOM is torn
down between tests (locate the describe block and the existing beforeEach in
EventFilters.test.ts to add the import and afterEach).
frontend/src/components/admin/events/__tests__/ReplayProgressBanner.test.ts (1)

1-3: Missing cleanup() in afterEach.

Same guideline violation — add cleanup() in afterEach.

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

In `@frontend/src/components/admin/events/__tests__/ReplayProgressBanner.test.ts`
around lines 1 - 3, The test file ReplayProgressBanner.test.ts is missing a
cleanup step after each test; import cleanup from '@testing-library/svelte'
alongside render and screen and add an afterEach(() => cleanup()) (or
afterEach(cleanup)) to ensure DOM is cleared between tests; update the top-level
imports and add the afterEach hook in the test file so tests using
render/screen/user are properly isolated.
frontend/src/components/admin/events/__tests__/EventsTable.test.ts (1)

1-3: Missing cleanup() in afterEach.

Same guideline violation — add cleanup() in afterEach.

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

In `@frontend/src/components/admin/events/__tests__/EventsTable.test.ts` around
lines 1 - 3, Add testing-library's cleanup to the test teardown: import cleanup
from '@testing-library/svelte' in EventsTable.test.ts and add an afterEach hook
that calls cleanup (e.g., afterEach(() => cleanup()) or afterEach(cleanup)) so
DOM is reset between tests; ensure the new afterEach is placed with the existing
beforeEach/vi setup so it always runs after each test.
frontend/src/components/editor/__tests__/OutputPanel.test.ts (1)

1-3: Missing cleanup() in afterEach.

Same guideline violation — add cleanup() in afterEach.

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

In `@frontend/src/components/editor/__tests__/OutputPanel.test.ts` around lines 1
- 3, Add a call to cleanup() in the test file's afterEach to ensure DOM is torn
down between tests: import cleanup from '@testing-library/svelte' (or include it
in the existing import from '@testing-library/svelte') and call cleanup() inside
the afterEach block in
frontend/src/components/editor/__tests__/OutputPanel.test.ts (the file
containing the describe/it tests), so the test suite cleans up rendered
components between cases.
🧹 Nitpick comments (2)
frontend/src/components/__tests__/NotificationCenter.test.ts (2)

303-308: Redundant local timerUser alias — use userWithTimers directly.

const timerUser = userWithTimers (lines 304 and 343) simply re-aliases the already-imported userWithTimers. The local variable adds noise without value; use userWithTimers directly at the call sites.

♻️ Proposed refactor
-      const timerUser = userWithTimers;
       render(NotificationCenter);
-      await timerUser.click(screen.getByRole('button', { name: /Notifications/i }));
+      await userWithTimers.click(screen.getByRole('button', { name: /Notifications/i }));
       screen.getByRole('button', { name: /View notification: Test/i }).focus();
-      await timerUser.keyboard('{Tab}');
+      await userWithTimers.keyboard('{Tab}');

Apply the same pattern for the second occurrence at lines 343–345.

Also applies to: 343-346

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

In `@frontend/src/components/__tests__/NotificationCenter.test.ts` around lines
303 - 308, Remove the redundant local alias "timerUser" and use the imported
"userWithTimers" directly in the test; specifically delete the declarations
`const timerUser = userWithTimers` and replace `timerUser.click` /
`timerUser.keyboard` calls with `userWithTimers.click` /
`userWithTimers.keyboard` in the NotificationCenter.test (both occurrences
around the existing calls to render(NotificationCenter) and keyboard/tab
interactions), leaving the rest of the assertions and setup (e.g.,
setNotifications, render, screen.getByRole) unchanged.

290-299: RegExp from variable — negligible risk in tests, but consider string matchers.

The static analyser flags lines 293 and 319 for constructing RegExp from a variable (subject/method), which could theoretically enable ReDoS if the input were attacker-controlled. In this test context the values are hardcoded test data, so there is no real security risk. However, replacing the dynamic RegExp with Testing Library's built-in string matching ({ name: /View notification: .../i } with a static literal, or using screen.findByText) removes the warning cleanly and makes intent clearer.

Also applies to: 315-324

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

In `@frontend/src/components/__tests__/NotificationCenter.test.ts` around lines
290 - 299, Replace the dynamic RegExp name match in the test with a plain string
matcher to avoid constructing a RegExp from the variable; in the test case that
uses interactionTestCases (the it.each block that builds subject from
method/hasUrl), call screen.findByRole('button', { name: `View notification:
${subject}` }) (and similarly for the other occurrence in the second block using
method/subject) instead of new RegExp(...) so the test uses a direct string
match; keep the rest of the flow (setNotifications, openDropdown,
interactWithButton, and assertions against
mocks.mockNotificationStore.markAsRead and mocks.mockGoto) unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@frontend/src/__tests__/test-utils.ts`:
- Around line 25-26: Exporting module-level singletons `user` and
`userWithTimers` causes shared internal keyboard/pointer state across tests;
replace them with factory functions (e.g., `createUser()` and
`createUserWithTimers()`) that call `userEvent.setup()` (and `userEvent.setup({
advanceTimers: vi.advanceTimersByTime })`) so each test can create a fresh
instance in beforeEach; update tests to declare a `let user: UserEventInstance`
and assign `user = createUser()` (or `createUserWithTimers()`) in beforeEach to
avoid cross-test pollution.

In `@frontend/src/components/admin/events/__tests__/ReplayPreviewModal.test.ts`:
- Around line 1-3: Add test cleanup and mock reset scaffolding: import cleanup
from '@testing-library/svelte' and use vi.hoisted() for any top-level mocks, add
beforeEach(() => { vi.clearAllMocks(); }) and afterEach(() => { cleanup(); }) in
this test file (ReplayPreviewModal.test.ts) — apply the same pattern to the
other affected files (EventFilters.test.ts, EventsTable.test.ts,
ReplayProgressBanner.test.ts, OutputPanel.test.ts, ResourceLimits.test.ts,
Settings.test.ts); reference the existing imports (describe, beforeEach, vi,
render) and the test harness utilities (user, screen) to place the new
beforeEach/afterEach blocks alongside them.

In `@frontend/src/components/editor/__tests__/SavedScripts.test.ts`:
- Around line 32-36: In renderAndExpand, after calling renderScripts(...) (which
calls render(SavedScripts,...)) await Svelte's tick before interacting: add
"await tick()" immediately after the renderScripts call and before the
user.click; if tick is not imported in this test file, import it from 'svelte'
(ensure renderAndExpand uses await tick() to let Svelte 5's reactive graph
settle before calling user.click on the "Show Saved Scripts" button).
- Around line 1-5: Add test lifecycle hooks to reset mocks and DOM between
tests: call vi.clearAllMocks() in a beforeEach hook and call cleanup() in an
afterEach hook (import cleanup from `@testing-library/svelte` if not present).
Also ensure the mock for '@lucide/svelte' is hoisted using vi.hoisted() per your
testing guidelines and pair renders that use render(...) and the shared user
singleton with await tick()/waitFor() where needed; reference the existing
top-level vi.mock(...) and the shared user from '$test/test-utils' when making
these additions.

---

Outside diff comments:
In `@frontend/src/components/__tests__/Header.test.ts`:
- Around line 60-79: Add vi.clearAllMocks() at the start of the beforeEach block
and call cleanup() in afterEach so all mocks/spies and mounted components are
fully reset between tests; update the existing beforeEach that currently calls
mocks.mockAuthStore.logout.mockReset() and others to also invoke
vi.clearAllMocks(), and add cleanup() alongside restoring window.innerWidth in
the afterEach that currently only resets originalInnerWidth.

In `@frontend/src/components/__tests__/NotificationCenter.test.ts`:
- Around line 152-172: The test setup should clear all mock state at the start
and unmount rendered components at the end: in the beforeEach block (where
mocks.mockAuthStore and others are initialized and many .mockReset() calls
occur) add a call to vi.clearAllMocks() to ensure mock histories are cleared
before each test, and in the afterEach block (which currently calls
vi.restoreAllMocks()) add a call to cleanup() to unmount any rendered
NotificationCenter instances; keep existing vi.restoreAllMocks() and console spy
handling intact.

In `@frontend/src/components/admin/events/__tests__/EventDetailsModal.test.ts`:
- Around line 25-28: The test suite for EventDetailsModal currently only clears
mocks in beforeEach but never unmounts rendered components; add an afterEach
hook that calls cleanup() to unmount and clean up DOM between tests (e.g., add
afterEach(() => { cleanup(); }) alongside the existing beforeEach that calls
vi.clearAllMocks()) so rendered components are properly torn down after each
test.

In `@frontend/src/components/editor/__tests__/LanguageSelect.test.ts`:
- Around line 1-28: Add test lifecycle hooks to this test file: import cleanup
from '@testing-library/svelte' at the top, then add a beforeEach that calls
vi.clearAllMocks() and an afterEach that calls cleanup(); place these hooks at
the top-level of the suite (e.g., inside the describe('LanguageSelect', ...)
block or file-level) so they run around tests that use renderSelect and
openMenu, ensuring mocks are reset and the DOM is cleaned between tests.

In `@frontend/src/components/editor/__tests__/ResourceLimits.test.ts`:
- Around line 1-9: Add the missing test setup/teardown: import cleanup from
'@testing-library/svelte' and add a beforeEach hook that calls
vi.clearAllMocks() and an afterEach hook that calls cleanup(); place these near
the top of ResourceLimits.test.ts so the suite resets mocks and DOM between
tests (referencing beforeEach, afterEach, vi.clearAllMocks, and cleanup to
locate where to add them).

In `@frontend/src/routes/__tests__/Notifications.test.ts`:
- Around line 1-43: The test suite is missing cleanup() after each test which
causes DOM nodes to accumulate; import cleanup from '@testing-library/svelte' at
the top alongside render/screen/waitFor and add an afterEach(() => cleanup())
block (keeping the existing beforeEach and vi.clearAllMocks) so each test's DOM
is torn down; reference the test file Notifications.test.ts and its beforeEach
and render usages to locate where to add the import and the afterEach call.

In `@frontend/src/routes/__tests__/Settings.test.ts`:
- Line 80: The test teardown is incomplete: ensure rendered components are
unmounted by calling cleanup() in the afterEach block and reset mocks at test
start by calling vi.clearAllMocks() in beforeEach; update the test file to call
cleanup() alongside vi.unstubAllGlobals() in the existing afterEach and add a
beforeEach that invokes vi.clearAllMocks() so tests don't leak DOM or mock state
(refer to afterEach, beforeEach, vi.unstubAllGlobals, cleanup,
vi.clearAllMocks).

---

Duplicate comments:
In `@frontend/src/components/admin/events/__tests__/EventFilters.test.ts`:
- Around line 1-3: The test file EventFilters.test.ts is missing an explicit
cleanup call after each test; import cleanup from '@testing-library/svelte' and
add an afterEach(() => cleanup()) alongside the existing beforeEach so the DOM
is torn down between tests (locate the describe block and the existing
beforeEach in EventFilters.test.ts to add the import and afterEach).

In `@frontend/src/components/admin/events/__tests__/EventsTable.test.ts`:
- Around line 1-3: Add testing-library's cleanup to the test teardown: import
cleanup from '@testing-library/svelte' in EventsTable.test.ts and add an
afterEach hook that calls cleanup (e.g., afterEach(() => cleanup()) or
afterEach(cleanup)) so DOM is reset between tests; ensure the new afterEach is
placed with the existing beforeEach/vi setup so it always runs after each test.

In `@frontend/src/components/admin/events/__tests__/ReplayProgressBanner.test.ts`:
- Around line 1-3: The test file ReplayProgressBanner.test.ts is missing a
cleanup step after each test; import cleanup from '@testing-library/svelte'
alongside render and screen and add an afterEach(() => cleanup()) (or
afterEach(cleanup)) to ensure DOM is cleared between tests; update the top-level
imports and add the afterEach hook in the test file so tests using
render/screen/user are properly isolated.

In `@frontend/src/components/editor/__tests__/OutputPanel.test.ts`:
- Around line 1-3: Add a call to cleanup() in the test file's afterEach to
ensure DOM is torn down between tests: import cleanup from
'@testing-library/svelte' (or include it in the existing import from
'@testing-library/svelte') and call cleanup() inside the afterEach block in
frontend/src/components/editor/__tests__/OutputPanel.test.ts (the file
containing the describe/it tests), so the test suite cleans up rendered
components between cases.

---

Nitpick comments:
In `@frontend/src/components/__tests__/NotificationCenter.test.ts`:
- Around line 303-308: Remove the redundant local alias "timerUser" and use the
imported "userWithTimers" directly in the test; specifically delete the
declarations `const timerUser = userWithTimers` and replace `timerUser.click` /
`timerUser.keyboard` calls with `userWithTimers.click` /
`userWithTimers.keyboard` in the NotificationCenter.test (both occurrences
around the existing calls to render(NotificationCenter) and keyboard/tab
interactions), leaving the rest of the assertions and setup (e.g.,
setNotifications, render, screen.getByRole) unchanged.
- Around line 290-299: Replace the dynamic RegExp name match in the test with a
plain string matcher to avoid constructing a RegExp from the variable; in the
test case that uses interactionTestCases (the it.each block that builds subject
from method/hasUrl), call screen.findByRole('button', { name: `View
notification: ${subject}` }) (and similarly for the other occurrence in the
second block using method/subject) instead of new RegExp(...) so the test uses a
direct string match; keep the rest of the flow (setNotifications, openDropdown,
interactWithButton, and assertions against
mocks.mockNotificationStore.markAsRead and mocks.mockGoto) unchanged.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ea55011 and d2e6b1a.

📒 Files selected for processing (23)
  • frontend/src/__tests__/test-utils.ts
  • frontend/src/components/__tests__/ErrorDisplay.test.ts
  • frontend/src/components/__tests__/Header.test.ts
  • frontend/src/components/__tests__/NotificationCenter.test.ts
  • frontend/src/components/admin/events/__tests__/EventDetailsModal.test.ts
  • frontend/src/components/admin/events/__tests__/EventFilters.test.ts
  • frontend/src/components/admin/events/__tests__/EventsTable.test.ts
  • frontend/src/components/admin/events/__tests__/ReplayPreviewModal.test.ts
  • frontend/src/components/admin/events/__tests__/ReplayProgressBanner.test.ts
  • frontend/src/components/editor/__tests__/LanguageSelect.test.ts
  • frontend/src/components/editor/__tests__/OutputPanel.test.ts
  • frontend/src/components/editor/__tests__/ResourceLimits.test.ts
  • frontend/src/components/editor/__tests__/SavedScripts.test.ts
  • frontend/src/routes/__tests__/Editor.test.ts
  • frontend/src/routes/__tests__/Login.test.ts
  • frontend/src/routes/__tests__/Notifications.test.ts
  • frontend/src/routes/__tests__/Register.test.ts
  • frontend/src/routes/__tests__/Settings.test.ts
  • frontend/src/routes/admin/__tests__/AdminEvents.test.ts
  • frontend/src/routes/admin/__tests__/AdminExecutions.test.ts
  • frontend/src/routes/admin/__tests__/AdminSagas.test.ts
  • frontend/src/routes/admin/__tests__/AdminSettings.test.ts
  • frontend/src/routes/admin/__tests__/AdminUsers.test.ts

Comment thread frontend/src/__tests__/test-utils.ts Outdated
Comment thread frontend/src/components/editor/__tests__/SavedScripts.test.ts Outdated
Comment thread frontend/src/components/editor/__tests__/SavedScripts.test.ts
Copy link
Copy Markdown

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

Choose a reason for hiding this comment

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

5 issues found across 23 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="frontend/src/components/admin/events/__tests__/EventDetailsModal.test.ts">

<violation number="1" location="frontend/src/components/admin/events/__tests__/EventDetailsModal.test.ts:3">
P3: Avoid using a shared `user` instance created at module scope. `userEvent.setup()` should be invoked inside each test or a setup helper so the document/device state is reset per test; importing the global instance risks cross-test state leakage and flakiness.</violation>
</file>

<file name="frontend/src/__tests__/test-utils.ts">

<violation number="1" location="frontend/src/__tests__/test-utils.ts:25">
P2: Avoid exporting a singleton user-event instance from shared utilities. Create a per-test helper that calls userEvent.setup() so tests get a fresh session and input state.</violation>
</file>

<file name="frontend/src/routes/__tests__/Register.test.ts">

<violation number="1" location="frontend/src/routes/__tests__/Register.test.ts:3">
P3: Using the shared `user` singleton from test-utils means the user-event instance (and its input state) is shared across test files. That can cause state leakage between tests and order-dependent failures when files run in the same worker. Prefer creating a fresh `userEvent.setup()` instance per test file or per test (e.g., in `beforeEach`) so input state is isolated.</violation>
</file>

<file name="frontend/src/components/__tests__/Header.test.ts">

<violation number="1" location="frontend/src/components/__tests__/Header.test.ts:3">
P2: The shared `user` instance is created at module scope and reused across all tests. Testing Library recommends calling `userEvent.setup()` inside each test/setup function to avoid shared input state between tests. Consider creating a fresh instance per test (e.g., inside `openUserDropdown`/`openMobileMenu` or each test) instead of importing the singleton.</violation>
</file>

<file name="frontend/src/routes/__tests__/Login.test.ts">

<violation number="1" location="frontend/src/routes/__tests__/Login.test.ts:3">
P2: Avoid importing the shared `user` singleton from test-utils; `userEvent.setup()` creates a stateful instance meant to be created per test/setup. Sharing one instance across test files can leak input state and cause flaky tests.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread frontend/src/__tests__/test-utils.ts Outdated
Comment thread frontend/src/components/__tests__/Header.test.ts
Comment thread frontend/src/routes/__tests__/Login.test.ts
Comment thread frontend/src/routes/__tests__/Register.test.ts
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Caution

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

⚠️ Outside diff range comments (1)
frontend/src/routes/__tests__/Privacy.test.ts (1)

1-11: ⚠️ Potential issue | 🟡 Minor

Add afterEach with cleanup() and vi.unstubAllGlobals().

Two guideline requirements are missing from the outer scope:

  1. cleanup() is never called — it must be called in afterEach per the project coding standards. Automatic cleanup fires only when import '@testing-library/svelte/vitest' is present in the Vitest setup file; relying on that without an explicit call violates the guideline regardless.
  2. vi.stubGlobal is called in beforeEach but vi.unstubAllGlobals() is never called, leaving window.scrollTo stubbed after the suite finishes, which could bleed into other test files running in the same worker.
🛡️ Proposed fix
-import { describe, it, expect, beforeEach, vi } from 'vitest';
-import { render, screen } from '@testing-library/svelte';
+import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
+import { render, screen, cleanup } from '@testing-library/svelte';
 import Privacy from '$routes/Privacy.svelte';

 const mocks = vi.hoisted(() => ({
   scrollTo: vi.fn(),
 }));

 beforeEach(() => {
   vi.stubGlobal('scrollTo', mocks.scrollTo);
 });

+afterEach(() => {
+  cleanup();
+  vi.unstubAllGlobals();
+});

Based on learnings: "Frontend tests must hoist mocks using vi.hoisted(); call cleanup() in afterEach and vi.clearAllMocks() in beforeEach."

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

In `@frontend/src/routes/__tests__/Privacy.test.ts` around lines 1 - 11, Add an
afterEach that calls cleanup() and vi.unstubAllGlobals(), and ensure mocks are
reset each run: keep the existing vi.hoisted usage of mocks and the beforeEach
that stubs scrollTo, but add a beforeEach call to vi.clearAllMocks() if not
present and an afterEach that calls cleanup() and vi.unstubAllGlobals() so the
scrollTo stub and other globals are removed and DOM is cleaned up after each
test; reference the existing beforeEach, mocks (vi.hoisted), and the test file
top-level setup when making the change.
🧹 Nitpick comments (1)
frontend/src/routes/__tests__/Privacy.test.ts (1)

18-23: Call await tick() after render() per the testing guideline.

render(Privacy) is synchronous in @testing-library/svelte v5, so await renderPrivacy() resolves immediately without flushing Svelte's microtask queue. The guideline requires await tick() after render. While Privacy is a static component and this doesn't cause observable failures today, it's an easy fix that keeps the test harness consistent and guards against regressions if the component later gains reactive state.

♻️ Proposed refactor
+import { tick } from 'svelte';
 ...
-  function renderPrivacy() {
-    return render(Privacy);
-  }
+  async function renderPrivacy() {
+    const result = render(Privacy);
+    await tick();
+    return result;
+  }

Based on learnings: "use await tick() after render and waitFor() for async state."

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

In `@frontend/src/routes/__tests__/Privacy.test.ts` around lines 18 - 23, The test
calls render(Privacy) via renderPrivacy() but doesn't await Svelte's microtask
queue; update the test to call await tick() after rendering to flush reactivity:
either add await tick() inside the helper renderPrivacy() (after
render(Privacy)) or call await tick() immediately after await renderPrivacy() in
the test, and ensure tick is imported from 'svelte' at the top of the file.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@frontend/src/routes/__tests__/Privacy.test.ts`:
- Around line 1-11: Add an afterEach that calls cleanup() and
vi.unstubAllGlobals(), and ensure mocks are reset each run: keep the existing
vi.hoisted usage of mocks and the beforeEach that stubs scrollTo, but add a
beforeEach call to vi.clearAllMocks() if not present and an afterEach that calls
cleanup() and vi.unstubAllGlobals() so the scrollTo stub and other globals are
removed and DOM is cleaned up after each test; reference the existing
beforeEach, mocks (vi.hoisted), and the test file top-level setup when making
the change.

---

Nitpick comments:
In `@frontend/src/routes/__tests__/Privacy.test.ts`:
- Around line 18-23: The test calls render(Privacy) via renderPrivacy() but
doesn't await Svelte's microtask queue; update the test to call await tick()
after rendering to flush reactivity: either add await tick() inside the helper
renderPrivacy() (after render(Privacy)) or call await tick() immediately after
await renderPrivacy() in the test, and ensure tick is imported from 'svelte' at
the top of the file.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5ff60e7 and b562d73.

⛔ Files ignored due to path filters (1)
  • frontend/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (5)
  • frontend/src/routes/__tests__/Editor.test.ts
  • frontend/src/routes/__tests__/Privacy.test.ts
  • frontend/src/routes/__tests__/Settings.test.ts
  • frontend/src/routes/admin/__tests__/AdminEvents.test.ts
  • frontend/src/routes/admin/__tests__/AdminSagas.test.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • frontend/src/routes/tests/Settings.test.ts
  • frontend/src/routes/tests/Editor.test.ts

Copy link
Copy Markdown

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

Choose a reason for hiding this comment

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

2 issues found across 26 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="frontend/src/routes/admin/__tests__/AdminLayout.test.ts">

<violation number="1" location="frontend/src/routes/admin/__tests__/AdminLayout.test.ts:26">
P3: These spies call through to the real `svelte-sonner` toast implementation. Without a mock/no-op implementation, the test will execute real toast side effects (DOM usage) instead of just tracking calls, which can make the suite flaky. Stub the methods (or mock the module) so the spies do not invoke the real toast behavior.</violation>
</file>

<file name="frontend/src/components/__tests__/Header.test.ts">

<violation number="1" location="frontend/src/components/__tests__/Header.test.ts:67">
P2: `vi.spyOn(router, 'goto')` leaves the real router navigation running during tests. Mock the implementation so clicks don’t trigger actual navigation side effects in jsdom.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread frontend/src/components/__tests__/Header.test.ts
Comment thread frontend/src/routes/admin/__tests__/AdminLayout.test.ts
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 16

Caution

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

⚠️ Outside diff range comments (2)
frontend/src/components/__tests__/ProtectedRoute.test.ts (2)

28-37: ⚠️ Potential issue | 🟡 Minor

vi.clearAllMocks() is missing from beforeEach.

The coding guidelines require vi.clearAllMocks() in every beforeEach. Without it, call counts and return-value overrides from prior tests bleed into subsequent ones. waitForInit.mockReset() covers only that one mock; all other vi.fn() instances on mockAuthStore (and the spy itself) keep stale history.

🛠️ Proposed fix
  beforeEach(() => {
+   vi.clearAllMocks();
    mocks.mockAuthStore.isAuthenticated = null;

Based on learnings: "call cleanup() in afterEach and vi.clearAllMocks() in beforeEach".

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

In `@frontend/src/components/__tests__/ProtectedRoute.test.ts` around lines 28 -
37, Add vi.clearAllMocks() at the start of the beforeEach setup to ensure prior
test spies/mocks are fully cleared; modify the beforeEach that currently resets
mocks.mockAuthStore.waitForInit and spies on router.goto so it begins with
vi.clearAllMocks(), then re-create any necessary spies (e.g., vi.spyOn(router,
'goto')) and reset/mock the specific store methods (e.g.,
mocks.mockAuthStore.waitForInit.mockReset().mockResolvedValue(true)) to avoid
stale call counts or return overrides leaking between tests.

74-82: ⚠️ Potential issue | 🟡 Minor

cleanup() is missing from afterEach.

The coding guidelines mandate cleanup() in every afterEach. Without it, rendered Svelte components accumulate in the document between tests, which can produce false-positive DOM queries or cross-test interference.

🛠️ Proposed fix
+import { render, screen, waitFor, cleanup } from '@testing-library/svelte';
 ...
  afterEach(() => {
+   cleanup();
    vi.restoreAllMocks();

Based on learnings: "call cleanup() in afterEach and vi.clearAllMocks() in beforeEach".

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

In `@frontend/src/components/__tests__/ProtectedRoute.test.ts` around lines 74 -
82, Tests are missing Svelte DOM cleanup and mock clearing: add a call to
cleanup() inside the existing afterEach block (alongside vi.restoreAllMocks()
and restoring window.sessionStorage/originalSessionStorage) and add
vi.clearAllMocks() to a beforeEach so mocks are cleared before each test; update
the afterEach surrounding code that references afterEach, vi.restoreAllMocks,
and originalSessionStorage to include cleanup() to prevent DOM leakage between
tests.
🧹 Nitpick comments (2)
frontend/vitest.config.ts (1)

18-22: Migrate environmentMatchGlobs to projects APIenvironmentMatchGlobs was deprecated in Vitest 3 and removed in Vitest 4.0.

Use Vitest's projects API instead, which supports setting different environment and setupFiles per project. This resolves the DOM/node setup file conflict by allowing you to define separate setupFiles for each environment.

Example:

projects: [
  {
    test: {
      name: 'node',
      include: ['src/lib/**/*.test.ts', 'src/stores/**/*.test.ts', 'src/utils/**/*.test.ts'],
      environment: 'node',
      setupFiles: ['./test/setup.node.ts'],
    },
  },
  // Add other projects as needed
]
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/vitest.config.ts` around lines 18 - 22, Replace the deprecated
environmentMatchGlobs usage in vitest.config.ts by defining a projects array
that maps the test globs to a named project with environment and setupFiles per
project; specifically remove environmentMatchGlobs and add a projects entry (use
the symbol projects) that contains a test object with name 'node', include set
to the patterns currently in environmentMatchGlobs (e.g.,
'src/lib/**/*.test.ts', 'src/stores/**/*.test.ts', 'src/utils/**/*.test.ts'),
environment: 'node', and setupFiles pointing to your node setup file
(setupFiles: ['./test/setup.node.ts']) so node-specific setup is applied only to
that project.
frontend/src/components/__tests__/ProtectedRoute.test.ts (1)

127-130: Replace setTimeout(resolve, 50) with await tick() (or waitFor) per guidelines.

Raw setTimeout waits are timing-dependent and can both flake (on slow CI) and waste time (on fast machines). The guideline requires await tick() after render for Svelte component updates.

🛠️ Proposed fix
+import { tick } from 'svelte';
 ...
-      await new Promise(resolve => setTimeout(resolve, 50));
+      await tick();

Based on learnings: "use await tick() after render and waitFor() for async state".

Also applies to: 139-142

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

In `@frontend/src/components/__tests__/ProtectedRoute.test.ts` around lines 127 -
130, Replace the raw setTimeout waits with Svelte/testing-library utilities:
import and call await tick() (from 'svelte') immediately after rendering the
ProtectedRoute component to wait for Svelte updates instead of using
setTimeout(resolve, 50), and for any asynchronous state assertions (e.g., where
you expect router.goto calls later) wrap those expectations in waitFor (from
'@testing-library/svelte') so the test waits reliably for async changes; update
occurrences that reference router.goto and the setTimeout pattern accordingly
(including the other similar instance in this test file).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@frontend/src/components/__tests__/Header.test.ts`:
- Around line 49-58: The test helpers openUserDropdown and openMobileMenu render
the Header but miss awaiting tick(), and the test file's lifecycle hooks should
call cleanup() in afterEach and reset mocks with vi.clearAllMocks() in
beforeEach; update openUserDropdown and openMobileMenu to call await tick()
immediately after render(Header), add afterEach(() => cleanup()) (or await
cleanup() if async) and change the manual mock resets in beforeEach to
vi.clearAllMocks() so mocks are fully cleared between tests.

In `@frontend/src/components/__tests__/ProtectedRoute.test.ts`:
- Line 4: Replace the failing vi.spyOn call on the sealed external ESM namespace
by mocking the module at load time: remove vi.spyOn(router, 'goto') and add
vi.mock('@mateothegreat/svelte5-router', { spy: true }) so the spy is created by
the mock; also add vi.clearAllMocks() at the top of the existing beforeEach to
reset mock history before each test, and call cleanup() inside afterEach to
teardown DOM between tests (referencing vi.mock, vi.clearAllMocks, and cleanup).

In `@frontend/src/components/editor/__tests__/LanguageSelect.test.ts`:
- Around line 1-3: Add the missing lifecycle hooks and flush rendering in
openMenu: inside the test suite's describe block, add beforeEach(() => {
vi.clearAllMocks(); }) and afterEach(() => { cleanup(); }) so mocks are reset
and DOM cleaned between tests, and in the openMenu helper (the function that
calls renderSelect) add await tick() immediately after renderSelect() to ensure
DOM updates are flushed before interacting with the menu; reference the describe
block, beforeEach, afterEach, vi.clearAllMocks, cleanup, openMenu, renderSelect,
and tick when applying the changes.

In `@frontend/src/routes/__tests__/Editor.test.ts`:
- Around line 132-136: Add an explicit cleanup step and ensure post-render
microtask flush: in the test teardown modify the afterEach block that currently
calls vi.unstubAllGlobals() to also call cleanup() (so both
vi.unstubAllGlobals() and cleanup() run), and change the render helper function
renderEditor to be async, call render(Editor) inside it, then await tick()
before returning to guarantee Svelte's post-render flush; update any test
callers to await renderEditor() accordingly.

In `@frontend/src/routes/__tests__/Home.test.ts`:
- Line 6: The mock for '@mateothegreat/svelte5-router' should be hoisted using
vi.hoisted(): create the mock functions (e.g., const goto = vi.fn()) inside a
vi.hoisted() call and then return them from the vi.mock() factory so the mock is
hoisted correctly; update the existing vi.mock(...) that returns { route: () =>
{}, goto: vi.fn() } to instead reference the hoisted goto and preserved route
symbol in the factory to follow project conventions.
- Around line 14-16: Make renderHome async and call await tick() immediately
after render(Home) so the Svelte microtask queue is flushed; update any tests
that call renderHome to still await it (e.g., replace synchronous renderHome()
with await renderHome()). Specifically change the renderHome helper (currently
returning render(Home)) to await render(Home) followed by await tick() before
returning the render result so subsequent waitFor/assertions run against flushed
state.
- Around line 1-2: Add missing test teardown/setup: update the vitest import to
include afterEach and ensure `@testing-library/svelte` import includes cleanup;
inside the describe for the Home tests add an afterEach that calls cleanup() and
vi.restoreAllMocks() (or vi.clearAllMocks() per project convention) to unmount
rendered components and restore spies (specifically the vi.spyOn on
meta.updateMetaTags), and keep the existing beforeEach to call
vi.clearAllMocks()/vi.hoisted() as needed so mocks are hoisted and tests do not
leak DOM or spies across specs.

In `@frontend/src/routes/__tests__/Login.test.ts`:
- Around line 46-48: The test helper renderLogin currently returns render(Login)
synchronously; change it to await tick() after calling render(Login) so the
helper becomes async and awaits tick() before returning, and add an afterEach
hook in the test suite that calls cleanup() to ensure DOM teardown between
tests; update references to the renderLogin helper calls to await the async
function where used and import tick and cleanup if not already present.

In `@frontend/src/routes/__tests__/Notifications.test.ts`:
- Around line 38-40: The test helper renderNotifications() does not await
Svelte's reactivity nor do tests call cleanup after each run; update the test
file to add an afterEach(() => cleanup()) and change renderNotifications to
await render(Notifications) followed by await tick() so the component mount
finishes before assertions (referencing renderNotifications, Notifications,
afterEach, cleanup, and tick).

In `@frontend/src/routes/__tests__/Register.test.ts`:
- Around line 35-37: The test lacks proper teardown and a render flush: update
the render helper and add an afterEach cleanup. Make the existing renderRegister
function async (function renderRegister() { ... }) and after calling
render(Register) await tick() to ensure the component is fully rendered before
assertions; also add an afterEach(() => cleanup()) to invoke cleanup() after
each test. Reference the renderRegister helper, the Register component,
afterEach, cleanup(), and tick() when making these edits.

In `@frontend/src/routes/admin/__tests__/AdminEvents.test.ts`:
- Line 12: The import userWithTimers is unused in AdminEvents.test.ts; remove
the userWithTimers import from the imports list to eliminate the unused symbol
warning and potential confusion—locate the import statement that includes
userWithTimers near the top of the test file and delete that identifier (or the
whole import if it becomes empty) while leaving the rest of the test imports and
the vi.useFakeTimers()/vi.advanceTimersByTimeAsync() timer-driven test intact.

In `@frontend/src/routes/admin/__tests__/AdminLayout.test.ts`:
- Around line 1-2: The tests in AdminLayout.test.ts are missing cleanup between
tests; import afterEach from 'vitest' and add an afterEach hook that calls
cleanup() from '@testing-library/svelte' to unmount DOM between tests; locate
the top-level imports (currently importing describe, it, expect, beforeEach, vi)
and add afterEach, and locate the setup block where beforeEach calls
vi.clearAllMocks() and insert an afterEach(() => cleanup()) to prevent DOM
leakage across tests.
- Around line 2-3: The renderLayout test helper currently returns synchronously
and must await Svelte's tick to stabilize async state: import tick from
'svelte', change the renderLayout helper function to be async, and call await
tick() (after render and before returning) so any pending microtasks update the
DOM; update any call sites if needed to await renderLayout. Ensure you modify
the renderLayout helper and its import lines (renderLayout, and the top-level
imports) accordingly.
- Line 21: The router mock is not hoisted and lifecycle cleanup/tick awaits are
missing; change the inline vi.mock call that defines
'@mateothegreat/svelte5-router' (currently using route: () => {}, goto: vi.fn())
to a hoisted mock like the authStore mock pattern, ensure the mocked exports
(route, goto) are declared at top-level hoisted scope, add an afterEach cleanup
block that clears mocks and unmounts (matching the test file's afterEach
pattern), and update renderLayout to await tick() after calling render so the
DOM updates settle before assertions (refer to renderLayout and the vi.mock for
router and authStore, plus afterEach and tick symbols).

In `@frontend/src/routes/admin/__tests__/AdminSettings.test.ts`:
- Around line 72-74: Make renderAdminSettings async and flush the component by
awaiting tick() after render: change function renderAdminSettings() to async,
call const result = render(AdminSettings); await tick(); return result. Import
tick from "svelte" and cleanup from "@testing-library/svelte", and update the
test teardown so afterEach calls cleanup() before vi.unstubAllGlobals() (e.g.,
afterEach(() => { cleanup(); vi.unstubAllGlobals(); })). Ensure the imports and
the async renderAdminSettings helper are used by the tests.

In `@frontend/vitest.config.ts`:
- Line 13: Replace the Vitest worker pool setting to improve jsdom stability:
locate the Vitest config object where pool: 'threads' is set (near the
environment: 'jsdom' setting) and change the value to pool: 'forks' so tests run
in separate processes instead of worker threads; update any related comments to
reflect the rationale for using forks with jsdom.

---

Outside diff comments:
In `@frontend/src/components/__tests__/ProtectedRoute.test.ts`:
- Around line 28-37: Add vi.clearAllMocks() at the start of the beforeEach setup
to ensure prior test spies/mocks are fully cleared; modify the beforeEach that
currently resets mocks.mockAuthStore.waitForInit and spies on router.goto so it
begins with vi.clearAllMocks(), then re-create any necessary spies (e.g.,
vi.spyOn(router, 'goto')) and reset/mock the specific store methods (e.g.,
mocks.mockAuthStore.waitForInit.mockReset().mockResolvedValue(true)) to avoid
stale call counts or return overrides leaking between tests.
- Around line 74-82: Tests are missing Svelte DOM cleanup and mock clearing: add
a call to cleanup() inside the existing afterEach block (alongside
vi.restoreAllMocks() and restoring window.sessionStorage/originalSessionStorage)
and add vi.clearAllMocks() to a beforeEach so mocks are cleared before each
test; update the afterEach surrounding code that references afterEach,
vi.restoreAllMocks, and originalSessionStorage to include cleanup() to prevent
DOM leakage between tests.

---

Nitpick comments:
In `@frontend/src/components/__tests__/ProtectedRoute.test.ts`:
- Around line 127-130: Replace the raw setTimeout waits with
Svelte/testing-library utilities: import and call await tick() (from 'svelte')
immediately after rendering the ProtectedRoute component to wait for Svelte
updates instead of using setTimeout(resolve, 50), and for any asynchronous state
assertions (e.g., where you expect router.goto calls later) wrap those
expectations in waitFor (from '@testing-library/svelte') so the test waits
reliably for async changes; update occurrences that reference router.goto and
the setTimeout pattern accordingly (including the other similar instance in this
test file).

In `@frontend/vitest.config.ts`:
- Around line 18-22: Replace the deprecated environmentMatchGlobs usage in
vitest.config.ts by defining a projects array that maps the test globs to a
named project with environment and setupFiles per project; specifically remove
environmentMatchGlobs and add a projects entry (use the symbol projects) that
contains a test object with name 'node', include set to the patterns currently
in environmentMatchGlobs (e.g., 'src/lib/**/*.test.ts',
'src/stores/**/*.test.ts', 'src/utils/**/*.test.ts'), environment: 'node', and
setupFiles pointing to your node setup file (setupFiles:
['./test/setup.node.ts']) so node-specific setup is applied only to that
project.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b562d73 and 98cdac2.

📒 Files selected for processing (26)
  • frontend/src/__tests__/test-utils.ts
  • frontend/src/components/__tests__/Header.test.ts
  • frontend/src/components/__tests__/ProtectedRoute.test.ts
  • frontend/src/components/admin/events/__tests__/EventDetailsModal.test.ts
  • frontend/src/components/admin/events/__tests__/EventsTable.test.ts
  • frontend/src/components/admin/events/__tests__/ReplayPreviewModal.test.ts
  • frontend/src/components/admin/events/__tests__/ReplayProgressBanner.test.ts
  • frontend/src/components/admin/events/__tests__/UserOverviewModal.test.ts
  • frontend/src/components/editor/__tests__/LanguageSelect.test.ts
  • frontend/src/components/editor/__tests__/OutputPanel.test.ts
  • frontend/src/components/editor/__tests__/ResourceLimits.test.ts
  • frontend/src/components/editor/__tests__/SavedScripts.test.ts
  • frontend/src/routes/__tests__/Editor.test.ts
  • frontend/src/routes/__tests__/Home.test.ts
  • frontend/src/routes/__tests__/Login.test.ts
  • frontend/src/routes/__tests__/Notifications.test.ts
  • frontend/src/routes/__tests__/Register.test.ts
  • frontend/src/routes/__tests__/Settings.test.ts
  • frontend/src/routes/admin/__tests__/AdminEvents.test.ts
  • frontend/src/routes/admin/__tests__/AdminExecutions.test.ts
  • frontend/src/routes/admin/__tests__/AdminLayout.test.ts
  • frontend/src/routes/admin/__tests__/AdminSagas.test.ts
  • frontend/src/routes/admin/__tests__/AdminSettings.test.ts
  • frontend/src/routes/admin/__tests__/AdminUsers.test.ts
  • frontend/vitest.config.ts
  • frontend/vitest.setup.ts
💤 Files with no reviewable changes (1)
  • frontend/src/components/admin/events/tests/UserOverviewModal.test.ts
🚧 Files skipped from review as they are similar to previous changes (4)
  • frontend/src/components/editor/tests/ResourceLimits.test.ts
  • frontend/src/components/editor/tests/OutputPanel.test.ts
  • frontend/src/routes/admin/tests/AdminExecutions.test.ts
  • frontend/src/routes/admin/tests/AdminSagas.test.ts

Comment thread frontend/src/components/__tests__/Header.test.ts
Comment thread frontend/src/components/__tests__/ProtectedRoute.test.ts
Comment thread frontend/src/components/editor/__tests__/LanguageSelect.test.ts
Comment thread frontend/src/routes/__tests__/Editor.test.ts
Comment thread frontend/src/routes/__tests__/Home.test.ts
Comment thread frontend/src/routes/admin/__tests__/AdminLayout.test.ts
Comment thread frontend/src/routes/admin/__tests__/AdminLayout.test.ts
Comment thread frontend/src/routes/admin/__tests__/AdminLayout.test.ts
Comment thread frontend/src/routes/admin/__tests__/AdminSettings.test.ts
Comment thread frontend/vitest.config.ts
Copy link
Copy Markdown

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

Choose a reason for hiding this comment

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

2 issues found across 22 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="frontend/src/lib/admin/stores/sagasStore.svelte.ts">

<violation number="1" location="frontend/src/lib/admin/stores/sagasStore.svelte.ts:25">
P2: Auto-refresh always calls loadSagas, which ignores the execution-specific endpoint used by loadExecutionSagas. After loading a specific execution, the next refresh will fetch a paged list of all sagas and then filter client-side, which can drop the execution’s items if they’re on a different page. Consider refreshing the execution endpoint when executionIdFilter is set.</violation>
</file>

<file name="frontend/src/lib/admin/stores/eventsStore.svelte.ts">

<violation number="1" location="frontend/src/lib/admin/stores/eventsStore.svelte.ts:112">
P2: Starting a new replay while a previous one is still polling will leave the old interval running. Clear any existing interval before creating a new one to avoid duplicate polling and leaks.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread frontend/src/lib/admin/stores/sagasStore.svelte.ts
Comment thread frontend/src/lib/admin/stores/eventsStore.svelte.ts Outdated
Copy link
Copy Markdown

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

Choose a reason for hiding this comment

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

1 issue found across 24 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="backend/tests/e2e/test_admin_events_routes.py">

<violation number="1" location="backend/tests/e2e/test_admin_events_routes.py:408">
P3: The SSE test can silently pass even if the stream never emits a `data:` payload, because the loop ends without any assertion. Track whether a status was received and assert it after the loop so missing data fails the test.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread backend/tests/e2e/test_admin_events_routes.py Outdated
Copy link
Copy Markdown

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

Choose a reason for hiding this comment

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

1 issue found across 1 file (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name=".github/actions/e2e-ready/action.yml">

<violation number="1" location=".github/actions/e2e-ready/action.yml:23">
P2: `kubectl wait` fails immediately when no nodes exist yet, so this can make the k3s init step flaky on slower startups. Consider looping until nodes exist/are ready rather than a single wait call.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread .github/actions/e2e-ready/action.yml
Copy link
Copy Markdown

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

Choose a reason for hiding this comment

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

1 issue found across 2 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="backend/tests/e2e/test_k8s_worker_create_pod.py">

<violation number="1">
P2: Ensure ConfigMap/Pod cleanup runs even when the test fails (e.g., wrap the create/verify block in a try/finally).</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

…lower-img-sizes

# Conflicts:
#	backend/app/settings.py
#	backend/tests/e2e/test_k8s_worker_create_pod.py
Copy link
Copy Markdown

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

Choose a reason for hiding this comment

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

4 issues found across 7 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="backend/tests/e2e/test_execution_routes.py">

<violation number="1" location="backend/tests/e2e/test_execution_routes.py:63">
P2: `submit_and_wait` can miss completion events because it subscribes to Redis Pub/Sub after execution starts, which introduces race-based test flakiness for fast jobs.</violation>

<violation number="2" location="backend/tests/e2e/test_execution_routes.py:210">
P2: Waiting for `POD_CREATED` via Pub/Sub after submit can miss the event and make cancellation tests flaky.</violation>
</file>

<file name="backend/tests/e2e/conftest.py">

<violation number="1" location="backend/tests/e2e/conftest.py:39">
P1: This per-call Redis pub/sub wait can miss already-published events, making E2E fixtures flaky due to a subscribe-after-produce race.</violation>

<violation number="2" location="backend/tests/e2e/conftest.py:196">
P1: Waiting for RESULT_STORED is not a reliable synchronization point for notification creation because result and notification handlers run in separate consumer groups.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread backend/tests/e2e/conftest.py Outdated
Comment thread backend/tests/e2e/conftest.py
# Wait for saga to start (pod creation command sent) instead of blind sleep
await event_waiter.wait_for_saga_command(exec_response.execution_id)
# Wait for pod creation (saga started + command dispatched) instead of blind sleep
await wait_for_pod_created(redis_client, exec_response.execution_id)
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot Feb 27, 2026

Choose a reason for hiding this comment

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

P2: Waiting for POD_CREATED via Pub/Sub after submit can miss the event and make cancellation tests flaky.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At backend/tests/e2e/test_execution_routes.py, line 210:

<comment>Waiting for `POD_CREATED` via Pub/Sub after submit can miss the event and make cancellation tests flaky.</comment>

<file context>
@@ -197,16 +198,16 @@ class TestExecutionCancel:
-        # Wait for saga to start (pod creation command sent) instead of blind sleep
-        await event_waiter.wait_for_saga_command(exec_response.execution_id)
+        # Wait for pod creation (saga started + command dispatched) instead of blind sleep
+        await wait_for_pod_created(redis_client, exec_response.execution_id)
 
         cancel_req = CancelExecutionRequest(reason="Test cancellation")
</file context>
Fix with Cubic

assert resp.status_code == 200
execution = ExecutionResponse.model_validate(resp.json())
await waiter.wait_for_result(execution.execution_id, timeout=timeout)
await wait_for_result(redis_client, execution.execution_id, timeout=timeout)
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot Feb 27, 2026

Choose a reason for hiding this comment

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

P2: submit_and_wait can miss completion events because it subscribes to Redis Pub/Sub after execution starts, which introduces race-based test flakiness for fast jobs.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At backend/tests/e2e/test_execution_routes.py, line 63:

<comment>`submit_and_wait` can miss completion events because it subscribes to Redis Pub/Sub after execution starts, which introduces race-based test flakiness for fast jobs.</comment>

<file context>
@@ -50,16 +51,16 @@
     assert resp.status_code == 200
     execution = ExecutionResponse.model_validate(resp.json())
-    await waiter.wait_for_result(execution.execution_id, timeout=timeout)
+    await wait_for_result(redis_client, execution.execution_id, timeout=timeout)
     result_resp = await client.get(f"/api/v1/executions/{execution.execution_id}/result")
     assert result_resp.status_code == 200
</file context>
Fix with Cubic

Copy link
Copy Markdown

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

Choose a reason for hiding this comment

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

1 issue found across 5 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="backend/tests/e2e/test_admin_events_routes.py">

<violation number="1" location="backend/tests/e2e/test_admin_events_routes.py:408">
P2: The replay SSE async generator is no longer closed in this test. Restore explicit `aclose()` (via `try/finally`) to avoid leaking generator state and async teardown flakiness.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment on lines +408 to 420
first_event = await anext(stream)
status = EventReplayStatusResponse.model_validate(
json_mod.loads(first_event["data"])
)

assert status_response.status_code == 200
status = EventReplayStatusResponse.model_validate(status_response.json())
assert status.session_id == replay_result.session_id
# After scheduling a replay (dry_run=False), status is SCHEDULED or RUNNING if it started quickly
assert status.status in (ReplayStatus.SCHEDULED, ReplayStatus.RUNNING)
assert status.status in (
ReplayStatus.SCHEDULED, ReplayStatus.CREATED,
ReplayStatus.RUNNING, ReplayStatus.COMPLETED,
)
assert status.total_events >= 1
assert status.replayed_events >= 0
assert status.progress_percentage >= 0.0

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot Feb 27, 2026

Choose a reason for hiding this comment

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

P2: The replay SSE async generator is no longer closed in this test. Restore explicit aclose() (via try/finally) to avoid leaking generator state and async teardown flakiness.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At backend/tests/e2e/test_admin_events_routes.py, line 408:

<comment>The replay SSE async generator is no longer closed in this test. Restore explicit `aclose()` (via `try/finally`) to avoid leaking generator state and async teardown flakiness.</comment>

<file context>
@@ -405,21 +405,18 @@ async def test_stream_replay_status_after_replay(
-            assert status.progress_percentage >= 0.0
-        finally:
-            await stream.aclose()
+        first_event = await anext(stream)
+        status = EventReplayStatusResponse.model_validate(
+            json_mod.loads(first_event["data"])
</file context>
Suggested change
first_event = await anext(stream)
status = EventReplayStatusResponse.model_validate(
json_mod.loads(first_event["data"])
)
assert status_response.status_code == 200
status = EventReplayStatusResponse.model_validate(status_response.json())
assert status.session_id == replay_result.session_id
# After scheduling a replay (dry_run=False), status is SCHEDULED or RUNNING if it started quickly
assert status.status in (ReplayStatus.SCHEDULED, ReplayStatus.RUNNING)
assert status.status in (
ReplayStatus.SCHEDULED, ReplayStatus.CREATED,
ReplayStatus.RUNNING, ReplayStatus.COMPLETED,
)
assert status.total_events >= 1
assert status.replayed_events >= 0
assert status.progress_percentage >= 0.0
try:
first_event = await anext(stream)
status = EventReplayStatusResponse.model_validate(
json_mod.loads(first_event["data"])
)
assert status.session_id == replay_result.session_id
assert status.status in (
ReplayStatus.SCHEDULED, ReplayStatus.CREATED,
ReplayStatus.RUNNING, ReplayStatus.COMPLETED,
)
assert status.total_events >= 1
assert status.replayed_events >= 0
assert status.progress_percentage >= 0.0
finally:
await stream.aclose()
Fix with Cubic

@sonarqubecloud
Copy link
Copy Markdown

@HardMax71 HardMax71 merged commit cb3f2e3 into main Feb 27, 2026
19 checks passed
@HardMax71 HardMax71 deleted the feat/lower-img-sizes branch February 27, 2026 07:07
This was referenced Feb 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants