Skip to content

chore: Update coerceTypes to false and modify mocharc settings#39559

Merged
ggazzo merged 66 commits intodevelopfrom
copilot/set-coercetypes-false
Mar 17, 2026
Merged

chore: Update coerceTypes to false and modify mocharc settings#39559
ggazzo merged 66 commits intodevelopfrom
copilot/set-coercetypes-false

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 12, 2026

We identified that all current validators in the system were allowing data coercion, which caused inconsistencies, especially in the OpenAPI. In some cases, coercion was being accepted, while in others, explicit tests rejected it. This ambiguity caused confusion, both in the documentation and in the code behavior. Since coercion is necessary for GET parameters (HTTP), as everything comes as a string, we created a new validator instance, specifically for these cases. In all other flows, we do not accept coercion and keep the types explicitly declared, ensuring greater predictability and consistency.

set coerceTypes to false /rest-typings/src/v1/Ajv.ts to see the impacts
also set apps/meteor/.mocharc.api.js bail: false to see all the places that will be affected


📱 Kick off Copilot coding agent tasks wherever you are with GitHub Mobile, available on iOS and Android.

Task: ARCH-2057

Copilot AI requested a review from ggazzo March 12, 2026 14:40
@dionisio-bot
Copy link
Copy Markdown
Contributor

dionisio-bot bot commented Mar 12, 2026

Looks like this PR is not ready to merge, because of the following issues:

  • This PR is missing the 'stat: QA assured' label

Please fix the issues and try again

If you have any trouble, please check the PR guidelines

@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Mar 12, 2026

🦋 Changeset detected

Latest commit: 3950b2e

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 41 packages
Name Type
@rocket.chat/rest-typings Minor
@rocket.chat/meteor Minor
@rocket.chat/api-client Patch
@rocket.chat/core-services Patch
@rocket.chat/ddp-client Patch
@rocket.chat/http-router Patch
@rocket.chat/models Patch
@rocket.chat/ui-contexts Major
@rocket.chat/web-ui-registration Major
@rocket.chat/account-service Patch
@rocket.chat/authorization-service Patch
@rocket.chat/ddp-streamer Patch
@rocket.chat/federation-matrix Patch
@rocket.chat/omnichannel-services Patch
@rocket.chat/presence Patch
rocketchat-services Patch
@rocket.chat/omnichannel-transcript Patch
@rocket.chat/presence-service Patch
@rocket.chat/queue-worker Patch
@rocket.chat/abac Patch
@rocket.chat/network-broker Patch
@rocket.chat/omni-core-ee Patch
@rocket.chat/livechat Patch
@rocket.chat/mock-providers Patch
@rocket.chat/cron Patch
@rocket.chat/instance-status Patch
@rocket.chat/omni-core Patch
@rocket.chat/server-fetch Patch
@rocket.chat/ui-client Major
@rocket.chat/media-calls Patch
@rocket.chat/uikit-playground Patch
@rocket.chat/fuselage-ui-kit Major
@rocket.chat/gazzodown Major
@rocket.chat/ui-avatar Major
@rocket.chat/ui-video-conf Major
@rocket.chat/ui-voip Major
@rocket.chat/core-typings Minor
@rocket.chat/apps Patch
@rocket.chat/model-typings Patch
@rocket.chat/license Patch
@rocket.chat/pdf-worker Patch

Not sure what this means? Click here to learn what changesets are.

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

@codecov
Copy link
Copy Markdown

codecov bot commented Mar 12, 2026

Codecov Report

❌ Patch coverage is 50.00000% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 70.89%. Comparing base (357bfcc) to head (3950b2e).
⚠️ Report is 21 commits behind head on develop.

Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##           develop   #39559      +/-   ##
===========================================
- Coverage    71.01%   70.89%   -0.12%     
===========================================
  Files         3199     3209      +10     
  Lines       113466   113892     +426     
  Branches     20574    20664      +90     
===========================================
+ Hits         80576    80746     +170     
- Misses       30845    31088     +243     
- Partials      2045     2058      +13     
Flag Coverage Δ
unit 71.54% <0.00%> (-0.18%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copilot AI and others added 5 commits March 13, 2026 09:23
…hema

With coerceTypes set to false, Ajv now strictly validates response
shapes. Users without statusText were failing validation since it was
marked as required. Update both the TypeScript type and the JSON schema
to reflect that statusText and avatarETag are optional fields.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
…lues for group and section

This change prepares for the migration of settings by allowing group and section properties to be null, ensuring compatibility with future updates. The upsertPermissions function has been adjusted to handle these changes accordingly.
…alidation

Introduce a new AJV instance (ajvQuery) in @rocket.chat/rest-typings with
coerceTypes: true, and use it for all query parameter validation across
the REST API. URL query strings always arrive as strings; with coercion
enabled, values like count=50 or offset=0 are coerced to numbers before
validation, so endpoints accept typical query shapes without failing.

- Add ajvQuery in packages/rest-typings (same options/formats/keywords
  as ajv, but coerceTypes: true) and export it.
- Use ajvQuery for inline query schemas in rooms, oauthapps, permissions,
  federation (ee), and for app-defined query validators in call-history,
  commands, custom-user-status, e2e.
- Switch all query-only validators in rest-typings to compile with
  ajvQuery (banners, customSounds, cloud, roles, autotranslate,
  integrations, import, calendar, videoConference, settings, moderation,
  email-inbox, misc, server-events, apps). Body and response validation
  continue to use the original ajv instance (no coercion).

Made-with: Cursor
@ggazzo ggazzo force-pushed the copilot/set-coercetypes-false branch from 0005782 to fcf39f2 Compare March 16, 2026 14:34
Updated the ICalendarEvent interface to permit meetingUrl to be explicitly set to null, enhancing flexibility in event data handling.
@ggazzo ggazzo force-pushed the copilot/set-coercetypes-false branch from fcf39f2 to eb12ef5 Compare March 16, 2026 14:59
ggazzo added 4 commits March 16, 2026 12:36
- apps/meteor app/api/server ajv.ts and v1/roles.ts
- rest-typings channels, chat, dm, groups, users query schemas using ajvQuery

Made-with: Cursor
Enhanced the BannerView type definition to allow the title property to accept either a plain string or a UiKit text object, improving flexibility in banner content representation.
Added a check in the UiKitBanner component to return null if the title is not a string, addressing potential issues with title rendering and ensuring proper type handling.
@ggazzo ggazzo force-pushed the copilot/set-coercetypes-false branch from b98800a to f49acdb Compare March 16, 2026 16:49
ggazzo added 6 commits March 16, 2026 14:42
Changed the expected error property in subscription tests from 'error-invalid-subscription' to 'invalid-params' and ensured the presence of a generic 'error' property for better clarity in error responses.
…ation

Updated the validation for GETLivechatRoomsParams to use the ajvQuery instance, enhancing query parameter validation with type coercion capabilities. This change ensures better handling of query parameters in the omnichannel API.
@ggazzo ggazzo force-pushed the copilot/set-coercetypes-false branch from 6b85726 to 30ee1ed Compare March 17, 2026 13:01
@ggazzo ggazzo marked this pull request as ready for review March 17, 2026 13:46
@ggazzo ggazzo requested review from a team as code owners March 17, 2026 13:46
@ggazzo ggazzo added this to the 8.3.0 milestone Mar 17, 2026
@ggazzo ggazzo removed the community label Mar 17, 2026
Copy link
Copy Markdown
Contributor

@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.

12 issues found across 86 files

Note: This PR contains a large number of files. cubic only reviews up to 75 files per PR, so some files may not have been reviewed.

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="packages/rest-typings/src/v1/subscriptionsEndpoints.ts">

<violation number="1" location="packages/rest-typings/src/v1/subscriptionsEndpoints.ts:107">
P1: Use the body Ajv instance here. `ajvQuery` enables type coercion for query strings, so this POST validator will start accepting numeric `roomId`/`_id` values by coercing them to strings.</violation>
</file>

<file name="packages/rest-typings/src/v1/chat.ts">

<violation number="1" location="packages/rest-typings/src/v1/chat.ts:3">
P2: This migration leaves three paginated GET validators on `ajv`, so `count`/`offset` query strings will now fail validation for those chat endpoints.</violation>
</file>

<file name="apps/meteor/app/authorization/server/functions/upsertPermissions.ts">

<violation number="1" location="apps/meteor/app/authorization/server/functions/upsertPermissions.ts:57">
P2: Omitting `group` here does not clear existing `group: null` / `section: null` values from stored permissions, so the intended normalization will be skipped.</violation>
</file>

<file name="packages/core-typings/src/ISetting.ts">

<violation number="1" location="packages/core-typings/src/ISetting.ts:56">
P2: Widen `section` as well; the new TODO says legacy settings can still contain `section: null`, so leaving it as `string` keeps this shared type unsound.</violation>
</file>

<file name="packages/rest-typings/src/v1/omnichannel.ts">

<violation number="1" location="packages/rest-typings/src/v1/omnichannel.ts:2353">
P2: This is a response schema, so switching it to `ajvQuery` weakens the contract by coercing mistyped output instead of failing validation.</violation>

<violation number="2" location="packages/rest-typings/src/v1/omnichannel.ts:2793">
P2: This POST body validator should keep `ajv`, not `ajvQuery`; using the query validator here will coerce invalid body fields instead of rejecting them.</violation>
</file>

<file name="apps/meteor/app/livechat/server/api/v1/integration.ts">

<violation number="1" location="apps/meteor/app/livechat/server/api/v1/integration.ts:31">
P2: This coercion runs too late to help clients affected by `coerceTypes: false`; schema validation will reject mistyped payloads before the handler executes.</violation>

<violation number="2" location="apps/meteor/app/livechat/server/api/v1/integration.ts:39">
P1: `null` timeout payloads now get stored as `undefined`, which breaks webhook retry timing and timeout handling downstream.</violation>
</file>

<file name="packages/rest-typings/src/v1/Ajv.ts">

<violation number="1" location="packages/rest-typings/src/v1/Ajv.ts:28">
P2: The format/keyword registrations are fully duplicated between `ajv` and `ajvQuery`. Extract the shared setup into a helper to avoid silent divergence when future formats or keywords are added to only one instance.

```ts
function configureAjv(instance: Ajv) {
  addFormats(instance);
  instance.addFormat('basic_email', /^[^@]+@[^@]+$/);
  instance.addFormat(
    'rfc_email',
    /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/,
  );
  instance.addKeyword({
    keyword: 'isNotEmpty',
    type: 'string',
    validate: (_schema: unknown, data: unknown): boolean => typeof data === 'string' && !!data.trim(),
  });
}
configureAjv(ajv);
configureAjv(ajvQuery);
```</violation>
</file>

<file name="apps/meteor/client/views/banners/UiKitBanner.tsx">

<violation number="1" location="apps/meteor/client/views/banners/UiKitBanner.tsx:56">
P2: This drops the entire banner for valid `TextObject` titles. `BannerView.title` explicitly allows `string | TextObject`, so apps sending structured titles will now lose the whole banner instead of just falling back on title rendering.</violation>
</file>

<file name="apps/meteor/server/services/calendar/service.ts">

<violation number="1" location="apps/meteor/server/services/calendar/service.ts:180">
P2: This makes it impossible to reliably clear an existing `meetingUrl`, because explicit clearing values are collapsed to `undefined` before the update payload is built.</violation>
</file>

<file name="packages/rest-typings/src/v1/misc.ts">

<violation number="1" location="packages/rest-typings/src/v1/misc.ts:98">
P2: `isDirectoryProps` is compiled against a type that incorrectly requires optional query fields.</violation>
</file>

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

Comment on lines +56 to 57
group?: string | null;
section?: string;
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot Mar 17, 2026

Choose a reason for hiding this comment

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

P2: Widen section as well; the new TODO says legacy settings can still contain section: null, so leaving it as string keeps this shared type unsound.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/core-typings/src/ISetting.ts, line 56:

<comment>Widen `section` as well; the new TODO says legacy settings can still contain `section: null`, so leaving it as `string` keeps this shared type unsound.</comment>

<file context>
@@ -52,7 +52,8 @@ export interface ISettingBase extends IRocketChatRecord {
 	env: boolean;
-	group?: string;
+	// TODO: migrate settings with group and section with null to undefined
+	group?: string | null;
 	section?: string;
 	tab?: string;
</file context>
Suggested change
group?: string | null;
section?: string;
group?: string | null;
section?: string | null;
Fix with Cubic

typeof LivechatHttpTimeout !== 'undefined' && { _id: 'Livechat_http_timeout', value: LivechatHttpTimeout },
typeof LivechatWebhookUrl !== 'undefined' && {
_id: 'Livechat_webhookUrl',
value: trim(LivechatWebhookUrl != null ? String(LivechatWebhookUrl) : ''),
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot Mar 17, 2026

Choose a reason for hiding this comment

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

P2: This coercion runs too late to help clients affected by coerceTypes: false; schema validation will reject mistyped payloads before the handler executes.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/meteor/app/livechat/server/api/v1/integration.ts, line 31:

<comment>This coercion runs too late to help clients affected by `coerceTypes: false`; schema validation will reject mistyped payloads before the handler executes.</comment>

<file context>
@@ -26,9 +26,18 @@ API.v1.addRoute(
-				typeof LivechatHttpTimeout !== 'undefined' && { _id: 'Livechat_http_timeout', value: LivechatHttpTimeout },
+				typeof LivechatWebhookUrl !== 'undefined' && {
+					_id: 'Livechat_webhookUrl',
+					value: trim(LivechatWebhookUrl != null ? String(LivechatWebhookUrl) : ''),
+				},
+				typeof LivechatSecretToken !== 'undefined' && {
</file context>
Fix with Cubic

'rfc_email',
/^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/,
);
ajvQuery.addFormat('basic_email', /^[^@]+@[^@]+$/);
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot Mar 17, 2026

Choose a reason for hiding this comment

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

P2: The format/keyword registrations are fully duplicated between ajv and ajvQuery. Extract the shared setup into a helper to avoid silent divergence when future formats or keywords are added to only one instance.

function configureAjv(instance: Ajv) {
  addFormats(instance);
  instance.addFormat('basic_email', /^[^@]+@[^@]+$/);
  instance.addFormat(
    'rfc_email',
    /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/,
  );
  instance.addKeyword({
    keyword: 'isNotEmpty',
    type: 'string',
    validate: (_schema: unknown, data: unknown): boolean => typeof data === 'string' && !!data.trim(),
  });
}
configureAjv(ajv);
configureAjv(ajvQuery);
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/rest-typings/src/v1/Ajv.ts, line 28:

<comment>The format/keyword registrations are fully duplicated between `ajv` and `ajvQuery`. Extract the shared setup into a helper to avoid silent divergence when future formats or keywords are added to only one instance.

```ts
function configureAjv(instance: Ajv) {
  addFormats(instance);
  instance.addFormat('basic_email', /^[^@]+@[^@]+$/);
  instance.addFormat(
    'rfc_email',
    /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/,
  );
  instance.addKeyword({
    keyword: 'isNotEmpty',
    type: 'string',
    validate: (_schema: unknown, data: unknown): boolean => typeof data === 'string' && !!data.trim(),
  });
}
configureAjv(ajv);
configureAjv(ajvQuery);
```</comment>

<file context>
@@ -10,18 +18,29 @@ const ajv = new Ajv({
 	'rfc_email',
 	/^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/,
 );
+ajvQuery.addFormat('basic_email', /^[^@]+@[^@]+$/);
+ajvQuery.addFormat(
+	'rfc_email',
</file context>
Fix with Cubic

});

// TODO: check why we are not considering TextObject as title
if (view.title && typeof view.title !== 'string') {
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot Mar 17, 2026

Choose a reason for hiding this comment

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

P2: This drops the entire banner for valid TextObject titles. BannerView.title explicitly allows string | TextObject, so apps sending structured titles will now lose the whole banner instead of just falling back on title rendering.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/meteor/client/views/banners/UiKitBanner.tsx, line 56:

<comment>This drops the entire banner for valid `TextObject` titles. `BannerView.title` explicitly allows `string | TextObject`, so apps sending structured titles will now lose the whole banner instead of just falling back on title rendering.</comment>

<file context>
@@ -52,6 +52,10 @@ const UiKitBanner = ({ initialView }: UiKitBannerProps) => {
 	});
 
+	// TODO: check why we are not considering TextObject as title
+	if (view.title && typeof view.title !== 'string') {
+		return null;
+	}
</file context>
Fix with Cubic

private async getMeetingUrl(eventData: Partial<ICalendarEvent>): Promise<string | undefined> {
if (eventData.meetingUrl !== undefined) {
return eventData.meetingUrl;
return eventData.meetingUrl || undefined;
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot Mar 17, 2026

Choose a reason for hiding this comment

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

P2: This makes it impossible to reliably clear an existing meetingUrl, because explicit clearing values are collapsed to undefined before the update payload is built.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/meteor/server/services/calendar/service.ts, line 180:

<comment>This makes it impossible to reliably clear an existing `meetingUrl`, because explicit clearing values are collapsed to `undefined` before the update payload is built.</comment>

<file context>
@@ -177,7 +177,7 @@ export class CalendarService extends ServiceClassInternal implements ICalendarSe
 	private async getMeetingUrl(eventData: Partial<ICalendarEvent>): Promise<string | undefined> {
 		if (eventData.meetingUrl !== undefined) {
-			return eventData.meetingUrl;
+			return eventData.meetingUrl || undefined;
 		}
 
</file context>
Fix with Cubic

};

export const isDirectoryProps = ajv.compile<Directory>(DirectorySchema);
export const isDirectoryProps = ajvQuery.compile<Directory>(DirectorySchema);
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot Mar 17, 2026

Choose a reason for hiding this comment

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

P2: isDirectoryProps is compiled against a type that incorrectly requires optional query fields.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/rest-typings/src/v1/misc.ts, line 98:

<comment>`isDirectoryProps` is compiled against a type that incorrectly requires optional query fields.</comment>

<file context>
@@ -95,7 +95,7 @@ const DirectorySchema = {
 };
 
-export const isDirectoryProps = ajv.compile<Directory>(DirectorySchema);
+export const isDirectoryProps = ajvQuery.compile<Directory>(DirectorySchema);
 
 type MethodCall = { method: string; params: unknown[]; id: string; msg: 'string' };
</file context>
Suggested change
export const isDirectoryProps = ajvQuery.compile<Directory>(DirectorySchema);
export const isDirectoryProps = ajvQuery.compile<PaginatedRequest<{ text?: string; type?: string; workspace?: string }>>(DirectorySchema);
Fix with Cubic

@ggazzo
Copy link
Copy Markdown
Member

ggazzo commented Mar 17, 2026

/jira ARCH-1464

KevLehman
KevLehman previously approved these changes Mar 17, 2026
Copy link
Copy Markdown
Contributor

@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 3 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="apps/meteor/app/livechat/server/api/v1/integration.ts">

<violation number="1" location="apps/meteor/app/livechat/server/api/v1/integration.ts:39">
P2: This truthiness check drops a valid timeout of `0`; use a null/undefined check so provided zero values are still saved.</violation>
</file>

<file name="packages/rest-typings/src/v1/omnichannel.ts">

<violation number="1" location="packages/rest-typings/src/v1/omnichannel.ts:3955">
P2: The new `| undefined` fields no longer match the Ajv schema, which still allows omitted and `null` values. That makes `isPOSTomnichannelIntegrations` narrow some valid payloads to the wrong TypeScript shape.</violation>
</file>

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

@ggazzo ggazzo force-pushed the copilot/set-coercetypes-false branch from 6c2e307 to c6ddf34 Compare March 17, 2026 20:15
KevLehman
KevLehman previously approved these changes Mar 17, 2026
This change introduces two separate AJV instances for validating request bodies and query parameters, enhancing type safety. The new setup prevents silent coercion of incorrect types in request bodies, ensuring that numeric and boolean values are sent with the correct types. This may break existing API consumers who rely on previous coercion behavior.
@ggazzo ggazzo merged commit 4c2e444 into develop Mar 17, 2026
14 of 15 checks passed
@ggazzo ggazzo deleted the copilot/set-coercetypes-false branch March 17, 2026 21:46
ggazzo added a commit that referenced this pull request Mar 25, 2026
Co-authored-by: copilot-swe-agent[bot] <[email protected]>
Co-authored-by: Guilherme Gazzo <[email protected]>
Co-authored-by: Guilherme Gazzo <[email protected]>
Co-authored-by: Claude Opus 4.6 <[email protected]>
ggazzo added a commit that referenced this pull request Mar 25, 2026
Co-authored-by: copilot-swe-agent[bot] <[email protected]>
Co-authored-by: Guilherme Gazzo <[email protected]>
Co-authored-by: Guilherme Gazzo <[email protected]>
Co-authored-by: Claude Opus 4.6 <[email protected]>
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.

3 participants