Skip to content

Release v0.9.4: job cancellation, telemetry opt-out, concurrency limits & motion UI#29

Merged
devarshishimpi merged 32 commits into
mainfrom
dev
Jul 11, 2026
Merged

Release v0.9.4: job cancellation, telemetry opt-out, concurrency limits & motion UI#29
devarshishimpi merged 32 commits into
mainfrom
dev

Conversation

@devarshishimpi

Copy link
Copy Markdown
Owner

Summary

This release bundles all dev work merged since v0.9.2, focused on job lifecycle control, review reliability under concurrency, and UI polish.

  • Job cancellation/deletion, in-memory GitHub token caching, and improved job status/continuation handling
  • Concurrency limits and timeout handling for model calls, plus subrequest budget handling for review jobs
  • Anonymous telemetry with an opt-out and secret override support
  • Custom file matcher support in diff parsing/review flow, new review performance settings
  • Motion-based sidebar navigation, tabs/select components, and Lenis smooth scrolling
  • Misc fixes: Google API test, sidebar active button colors, onMouseEnter typecheck
  • Dependency bump for known vulnerable packages

See CHANGELOG.md for the full breakdown.

Version bumped: 0.9.20.9.4 (package.json, package-lock.json, SECURITY.md).

Test plan

  • CI passes (build, lint, test suite)
  • Smoke test job cancellation/deletion flow
  • Smoke test telemetry opt-out toggle
  • Verify dashboard "About" section shows v0.9.4

- Deleted DLQ API routes and associated types from the client and server.
- Removed DLQ message handling from the JobsPage component.
- Cleaned up server-side job processing logic to eliminate DLQ dependencies.
- Introduced a new ReviewWorkflow to manage job phases and execution.
- Updated job schema to include workflow instance ID.
- Refactored review job handling to support new workflow structure.
- Adjusted tests to reflect changes in job processing and workflow management.
…king

Feat: Add anonymous telemetry, UI enhancements, and remove DLQ
- Implemented database migration to insert default review settings.
- Created a SteppedSlider component for selecting concurrency levels and max comments.
- Added ConfirmDialog component for user confirmation on exceeding limits.
- Updated SettingsPage to manage and display review settings with automatic saving.
- Introduced API routes for fetching and updating review settings.
- Enhanced review logic to respect concurrency and comment limits based on user settings.
- Updated the stats page to improve the layout and structure of metrics display, consolidating various graph components into a more cohesive MetricsGrid component.
- Removed unused properties (rpm, tpm, rpd) from model configurations in the database schema and related queries.
- Enhanced the stats retrieval function to include additional metrics such as job statuses, triggers, severities, categories, and performance metrics.
- Updated the shared schema to reflect changes in the stats structure, including new fields for statuses, triggers, severities, categories, and performance.
- Adjusted API model routes and validation schemas to remove references to removed properties.
- Updated tests to align with the new data structure and ensure proper functionality.
…ew settings API, and add tests for concurrency limits
… handling

- Updated jobStatuses to include 'cancelled' in schema.
- Implemented API endpoint to stop ongoing jobs, marking them as 'cancelled'.
- Added API endpoint for job deletion, ensuring jobs are removed from processing.
- Introduced tests for stopping and deleting jobs, verifying correct status updates.
- Enhanced review flow to inherit parent reviews correctly based on model configurations.
- Added async batch review tests to ensure proper handling of review submissions and polling.
- Improved error handling for Cloudflare model responses, ensuring failures are correctly reported.
- Updated token tracker to reflect new safe margin limits and ensure budget tracking is accurate.
- Added scheduled maintenance tests to verify proper handling of active jobs and maintenance work.
refactor(db): remove batchInsertFileReviews function and related logic

feat(jobs): add setJobPullRequestMeta to refresh job PR metadata

refactor(jobs): remove startJobProcessing and recoverStaleJobs functions

fix(model): cap in-call retry delay for Google 429 responses

feat(model): classify 5xx errors as transient for retry logic

feat(transient-errors): create shared transient error handling utilities

test(model): add tests for transient error classification and retry logic

test(review): ensure queued jobs respect concurrency limits while running jobs do not
…currency-refactor

Feat: Review reliability and performance overhaul and UI refactor
chatgpt-codex-connector[bot]

This comment was marked as resolved.

@codra-app-personal codra-app-personal 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.

Codra Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 08c954523f

ℹ️ About Codra in GitHub

Your team has set up Codra to review pull requests in this repo. Reviews are triggered when you:

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codra-app review"

If Codra has suggestions, it will comment; otherwise it will react with 👍.

Codra can also answer questions or update the PR. Try commenting "@codra-app address that feedback".

Note

93 comments were omitted from this review to reduce noise and respect the configured max_comments limit (10). Showing the most critical issues.

Comment thread src/client/lib/api.ts
@@ -174,6 +172,21 @@ export const api = {
method: 'POST',
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P0 Missing Import for RetryJobResponse

The newly introduced rerunJob and stopJob methods in the api object use RetryJobResponse, but this type is not imported from the shared package, leading to a TypeScript compilation error.

Suggested change
});
Import 'RetryJobResponse' from '@shared/api' or define it in the imports section.

children?: ReactNode;
}>;
const childKey = el.key ? String(el.key) : `item-${index}`;
return cloneElement(

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P0 Infinite React Element Cloning Loop / Stack Overflow

The cloneElement function is called within the .map of children, where the children being rendered inside the clone contains the original child element el. This creates a recursive structure where the component attempts to render children infinitely (or until the call stack limits are reached), as it keeps nesting the component structure within itself every time the child is cloned.

Comment thread scripts/migrate.mjs
await query(
`
INSERT INTO model_configs (model_id, rpm, tpm, rpd, provider, provider_id, model_name, updated_at)
SELECT $1, 10, 131072, 300, 'cloudflare', p.id, $1, now()

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Potential Data Integrity Issue: Column removal without schema update

The migration removes default values and insert logic for 'rpm', 'tpm', and 'rpd' columns, but the database schema itself still contains these columns. If these columns have 'NOT NULL' constraints or application code depends on them, this will cause runtime failures. Ensure the database schema migration corresponds to these application-level changes to prevent 'null value violates not-null constraint' errors.

Suggested change
SELECT $1, 10, 131072, 300, 'cloudflare', p.id, $1, now()
Ensure the database table 'model_configs' has been altered to allow NULLs for 'rpm', 'tpm', and 'rpd' columns if they are not being dropped, or execute ALTER TABLE DROP COLUMN if they are no longer required.

}
}

const jobsSpinner = ora('Creating jobs queue (codra-review-jobs)...').start();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Removal of DLQ configuration logic leads to stale environment variables

The removal of the DLQ creation and ID extraction logic means that the 'CF_DLQ_ID' environment variable in 'wrangler.jsonc' will no longer be automatically updated. If the DLQ queue ID changes or is required for the application to function correctly, the setup process will fail or persist with incorrect/null configuration values without warning the user.

Suggested change
const jobsSpinner = ora('Creating jobs queue (codra-review-jobs)...').start();
If the DLQ is no longer managed by this script, ensure the infrastructure-as-code documentation or the application bootstrap logic accounts for the missing 'CF_DLQ_ID' and provides a clear fallback or validation mechanism.

<div>
<p className="text-xs font-semibold uppercase tracking-widest text-primary/70 mb-1">
{category}
</p>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Category display logic removed

The category prop was made optional, but the code that renders the category text (the paragraph element) was completely removed from the component. This ignores the intent of the prop change and makes it impossible to display the category in the UI.

Suggested change
</p>
{category && <p className="text-xs font-semibold uppercase tracking-widest text-primary/70 mb-1">{category}</p>}

</button>
</motion.li>
);
})}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Unsafe Portal usage in Server Side Rendering (SSR) environments

The component uses 'document.body' directly in the createPortal call. In Next.js or other SSR frameworks, this code will throw an error on the server side because 'document' is undefined. Always check for the existence of 'document' or use a 'mounted' state/useEffect to render the portal only on the client.

Suggested change
})}
const [mounted, setMounted] = useState(false);
useEffect(() => setMounted(true), []);
if (!mounted) return null;
return createPortal(..., document.body);

@@ -398,7 +398,7 @@ export function parseFileReviewResponse(raw: string, file: FileDiff): {
while (current !== prev) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Potential Infinite Loop in String Sanitization

The while loop condition current !== prev relies on the regex replacement strictly decreasing the length or modifying the string. If the regex fails to match characters but the string structure results in an infinite loop due to non-converging state or specific character encodings, the server will block the event loop, causing a denial-of-service. While the current regex seems safer, it lacks an iteration limit to prevent hanging.

Suggested change
while (current !== prev) {
let iterations = 0; while (current !== prev && iterations < 10) { iterations++; ... }

Comment thread src/server/db/client.ts
// Reused clients for the no-runWithDb() fallback path below. Keyed by connection string so a caller
// that queries outside a runWithDb() scope shares one bounded pool instead of leaking a fresh pool
// (up to `max` connections) on every single query.
const fallbackClients = new Map<string, DbClient>();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Unbounded Map Memory Leak

The fallbackClients Map stores database clients indefinitely for every unique connection string encountered. If env.HYPERDRIVE.connectionString is dynamic or if there are many unique environments during test execution, this will result in a permanent memory leak as entries are never removed.

Suggested change
const fallbackClients = new Map<string, DbClient>();
Use a Least Recently Used (LRU) cache or a WeakMap if applicable, or implement a cleanup mechanism for entries no longer needed by the test suite.

Comment thread src/server/core/review.ts
verdict: verdictSummary.verdict,
severityDistribution,
});
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Error-handling risk in NextPhaseError mechanism

The enqueueJobPhase function now throws a NextPhaseError. If this is caught by a broader generic catch block somewhere upstream that doesn't explicitly look for this custom error type, it could result in the job being erroneously marked as failed or having its state corrupted rather than triggering the expected phase transition.

Suggested change
}
Ensure the top-level job runner catch block explicitly checks for `NextPhaseError` and handles the queueing/delay logic properly instead of relying on an implicit re-throw.

Comment thread src/server/env.ts
@@ -29,6 +29,7 @@ export interface AppBindings {
AI: WorkersAiBinding;
APP_KV: KVNamespace;
REVIEW_QUEUE: QueueProducer<ReviewJobMessage>;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Missing definition for Workflow type

The interface 'AppBindings' now references a type 'Workflow' at line 32, but this type is not imported or defined within the provided file scope. This will cause a compilation error.

Suggested change
REVIEW_QUEUE: QueueProducer<ReviewJobMessage>;
import type { Workflow } from '@cloudflare/workers-types';

Repository owner deleted a comment from github-advanced-security AI Jul 10, 2026
chatgpt-codex-connector[bot]

This comment was marked as resolved.

codra-app-personal[bot]

This comment was marked as resolved.

codra-app-personal[bot]

This comment was marked as resolved.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

@codra-app-personal codra-app-personal 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.

Codra Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0af847f33d

ℹ️ About Codra in GitHub

Your team has set up Codra to review pull requests in this repo. Reviews are triggered when you:

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codra-app review"

If Codra has suggestions, it will comment; otherwise it will react with 👍.

Codra can also answer questions or update the PR. Try commenting "@codra-app address that feedback".

Note

94 comments were omitted from this review to reduce noise and respect the configured max_comments limit (10). Showing the most critical issues.

Comment thread src/client/lib/api.ts
@@ -174,6 +172,21 @@ export const api = {
method: 'POST',

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P0 Missing Import for RetryJobResponse

The newly added functions 'rerunJob' and 'stopJob' return a Promise of 'RetryJobResponse', but this type is not imported from '@shared/api'. This will cause a compilation error.

Suggested change
method: 'POST',
Add 'RetryJobResponse' to the import list from '@shared/api' at the top of the file.

Comment thread scripts/migrate.mjs
await query(
`
INSERT INTO model_configs (model_id, rpm, tpm, rpd, provider, provider_id, model_name, updated_at)
SELECT $1, 10, 131072, 300, 'cloudflare', p.id, $1, now()

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Implicit column dependency risk

The migration removes 'rpm', 'tpm', and 'rpd' from INSERT/UPDATE operations. If these columns are defined as 'NOT NULL' in the database schema without default values, this migration will cause runtime SQL errors during execution.

Suggested change
SELECT $1, 10, 131072, 300, 'cloudflare', p.id, $1, now()
Ensure the database schema has DEFAULT values for rpm, tpm, and rpd columns before removing them from the migration queries.

}
}

const jobsSpinner = ora('Creating jobs queue (codra-review-jobs)...').start();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Removal of DLQ configuration logic

The script removes the logic to create, fetch, and configure the 'codra-review-dlq' queue in 'wrangler.jsonc'. If this queue is a mandatory dependency for the application's functionality, its removal will cause runtime failures when the application expects this environment variable or resource to exist. Ensure that 'CF_DLQ_ID' is still being populated via another mechanism or is no longer required.

Suggested change
const jobsSpinner = ora('Creating jobs queue (codra-review-jobs)...').start();
Verify if the DLQ queue is still needed and update the configuration strategy if necessary.

} finally {
setIsStopping(false);
}
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 State inconsistency in handleDelete error path

In the handleDelete function, the setIsDeleting(false) call is placed inside the catch block, but it is missing from the finally block or a potential success path if the toast logic is refactored. More importantly, if api.deleteJob throws, the state remains isDeleting: true because setIsDeleting(false) is only called inside the catch, and if an error occurs outside of that specific block (or if the logic is extended), it could lead to an inconsistent UI state. It is safer to use a finally block for state cleanup.

Suggested change
};
try { await api.deleteJob(job.id); toast.success('Job deleted.', { id: t }); navigate('/jobs'); } catch (e) { ... } finally { setIsDeleting(false); }

Comment thread src/server/core/diff.ts
}
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Logical flaw in chunkFileDiff leading to data duplication

In chunkFileDiff, the final chunk is always marked as 'isTruncated: true', even if it contains the remainder of the file and does not exceed the line limits. This will cause downstream consumers to incorrectly label perfectly valid file chunks as being truncated.

Suggested change
Set 'isTruncated' to false in the final chunk if it wasn't split during the process, or evaluate if truncation is truly necessary.

prev = current;
current = current
.replace(/^([\u{1F300}-\u{1F9FF}]|\[QUALITY\]|\[SECURITY\]|\[BUG\]|\[PERFORMANCE\]|\[CORRECTNESS\]|\[P[0-3]\]|\[NIT\]|QUALITY|SECURITY|BUG|P[0-3]|NIT|[:\-\s\uFE0F]|[^\w\s])+/giu, '')
.replace(/^(?:[^\w\s]+|(?:QUALITY|SECURITY|BUG|PERFORMANCE|CORRECTNESS|P[0-3]|NIT)\b)+/giu, '')

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Catastrophic Backtracking Potential in Regex

The regex used in the replacement operation contains a non-capturing group with repeated alternatives: (?:[^w\s]+|(?:...))+. Because both the character class [^\w\s]+ and the specific keywords can overlap or match sequences in complex ways, specifically if the input is malformed or maliciously crafted, this could lead to exponential backtracking (Catastrophic Backtracking). While the regex is anchored to the start of the string, complex nested repetitions should be evaluated for performance impact on long strings.

Suggested change
.replace(/^(?:[^\w\s]+|(?:QUALITY|SECURITY|BUG|PERFORMANCE|CORRECTNESS|P[0-3]|NIT)\b)+/giu, '')
Ensure the input string is truncated or limited in length before applying the regex to prevent ReDoS.

superseded: { conclusion: 'neutral' as const, title: 'Review superseded', summary: 'Superseded by a newer commit or job.' },
cancelled: { conclusion: 'cancelled' as const, title: 'Review stopped', summary: 'Stopped by user.' },
failed: { conclusion: 'failure' as const, title: 'Review failed', summary: 'Review failed.' },
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Unsafe casting of job status in check-run completion

The code uses a type assertion job.status as keyof typeof checkRunPresentation to access the checkRunPresentation object. If job.status contains a value not present in the object keys (e.g., if a new status like 'pending' or 'running' is added to the database), the fallback logic will use checkRunPresentation.failed, potentially reporting an inaccurate state to GitHub.

Suggested change
};
const statusKey = job.status in checkRunPresentation ? (job.status as keyof typeof checkRunPresentation) : 'failed'; const presentation = checkRunPresentation[statusKey];

Comment thread src/server/db/client.ts
// Reused clients for the no-runWithDb() fallback path below. Keyed by connection string so a caller
// that queries outside a runWithDb() scope shares one bounded pool instead of leaking a fresh pool
// (up to `max` connections) on every single query.
const fallbackClients = new Map<string, DbClient>();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Unbounded Map growing causing potential memory leaks

The fallbackClients Map stores database clients indefinitely. While the developer assumes this is only used in tests, if env.HYPERDRIVE.connectionString values vary or if the application environment changes, the Map will never be cleared, leading to a memory leak of database connection pools.

Suggested change
const fallbackClients = new Map<string, DbClient>();
Use a mechanism to expire entries or explicitly clear the cache if the environment is destroyed. For testing specifically, consider a cleanup hook to clear the map.

rpm: optionalLimitSchema,
tpm: optionalLimitSchema,
rpd: optionalLimitSchema,
}).strict();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Removal of concurrency limit validation schema

The removal of 'rpm', 'tpm', and 'rpd' from 'modelConfigUpdateSchema' without providing an alternative validation logic or updating the request handler indicates a potential regression where users can no longer update concurrency limits, or worse, the system may now accept unvalidated or malformed input for these fields if the underlying database layer expects them.

Suggested change
}).strict();
If these fields are still used in the application, they should remain in the schema with proper validation. If they are no longer supported, ensure the update logic handles the omission explicitly to avoid partial updates.

Comment thread wrangler.jsonc
@@ -50,7 +50,6 @@
"consumers": [
{
"queue": "codra-review-jobs",

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Removal of Dead Letter Queue Configuration

The 'dead_letter_queue' configuration was removed from the queue consumer. Without a DLQ, messages that fail processing repeatedly will be permanently lost or block the queue processing, significantly reducing the system's fault tolerance for 'codra-review-jobs'.

Suggested change
"queue": "codra-review-jobs",
Restore "dead_letter_queue": "codra-review-dlq" to the consumer configuration.

@devarshishimpi
devarshishimpi merged commit 3fb6122 into main Jul 11, 2026
6 checks passed

@codra-app-personal codra-app-personal 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.

Codra Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0af847f33d

ℹ️ About Codra in GitHub

Your team has set up Codra to review pull requests in this repo. Reviews are triggered when you:

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codra-app review"

If Codra has suggestions, it will comment; otherwise it will react with 👍.

Codra can also answer questions or update the PR. Try commenting "@codra-app address that feedback".

Note

10 findings were omitted to reduce noise — low-confidence, duplicate, or unverified findings are filtered out, and the review is capped at max_comments (5). Showing the most critical issues.

Comment thread src/server/core/diff.ts
}

const chunks: FileDiff[] = [];
let currentHunks: DiffHunk[] = [];

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P0 Infinite loop in chunkFileDiff logic

In the chunkFileDiff function, if roomInChunk is less than or equal to 0, the code pushes the current chunk and continues to the next iteration of the while loop without consuming any part of the linesRemainingInHunk array or advancing the state. Because linesRemainingInHunk remains the same and currentLines is reset to 0, roomInChunk becomes maxLinesPerChunk again, but this logic can lead to infinite loops if hunk.lines are not processed correctly in the loop cycle. More critically, if linesRemainingInHunk has elements but roomInChunk <= 0, the loop resets and re-evaluates the exact same state infinitely.

Suggested change
let currentHunks: DiffHunk[] = [];
The logic should handle the overflow by breaking the hunk even if it's the first line, or adjusting the `while` structure to ensure progress is made every iteration.

outputTokens: data.usageMetadata?.candidatesTokenCount ?? 0,
modelUsed: model,
provider: config.providerName ?? 'Google',
logger.error(`Gemini request failed with ${response.status}`, logData);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P0 Use of uninitialized startTime variable

The variable startTime is referenced on line 176 to calculate the duration of the API call, but it is never defined or assigned a value within the scope of the reviewWithGoogle function. This will cause a ReferenceError at runtime when a successful response is received.

Suggested change
logger.error(`Gemini request failed with ${response.status}`, logData);
Add `const startTime = Date.now();` at the beginning of the `reviewWithGoogle` function.

children?: ReactNode;
}>;
const childKey = el.key ? String(el.key) : `item-${index}`;
return cloneElement(

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P0 Infinite React element nesting via cloneElement

The SharedLayoutBg component uses cloneElement to wrap each child in a new set of nodes that includes the child itself (via {el} at line 110). Because Children.toArray(children) includes all original children and the logic injects the child back into the cloned version, this creates a recursive nesting structure (Child -> [Wrapper -> Child] -> [Wrapper -> Child]...). This will result in a Maximum Update Depth exceeded error or a stack overflow in React upon the first render.

Suggested change
return cloneElement(
The component should wrap the children in a container rather than using cloneElement to inject the background into the children themselves, or use a context-based approach to share activeId state.

</motion.button>

</div>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Unsafe access to document.body in server-side environment

The code calls createPortal(..., document.body) directly in the component body. In a Next.js or SSR-based React application, document is undefined during server-side rendering, which will throw a ReferenceError. Portals should be rendered inside a useEffect or checked for existence.

Suggested change
const [mounted, setMounted] = useState(false);
useEffect(() => setMounted(true), []);
if (!mounted) return null;
return createPortal(..., document.body);

Comment thread src/client/app.css
border-color: oklch(24% 0.025 115) !important;
color: oklch(88% 0.008 115) !important;
}
/* ── SUCCESS / ERROR / LOADING ─────────────────────

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Broken toast notification styles due to missing background properties

The CSS changes removed the background property from toast status variants (.codra-toast-warning, .codra-toast-info, etc.) while keeping the text color declarations. Since the default .codra-toast class defines a specific background color and the status variants previously overrode it, toasts will now fall back to the default background color, potentially losing the visual status indication (e.g., info/warning backgrounds) originally intended to help users differentiate toast types.

Suggested change
/* ── SUCCESS / ERROR / LOADING ─────────────────────
Restore the background color properties to the status-specific toast classes or redefine them using CSS variables to ensure visual distinction.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant