From e82a5951df4199385bede98b697a98ca11e4caaa Mon Sep 17 00:00:00 2001 From: Basil Kotov Date: Mon, 2 Mar 2026 12:07:17 +0000 Subject: [PATCH 1/2] fix: omit server-generated fields from nested CustomerSchema in CreateSalesOrderInput MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CreateSalesOrderInputSchema omitted immutable fields (id, createdAt, updatedAt, tenantId) from the top-level OrderSchema, but the nested CustomerSchema still inherited them as required from ObjectProps. This caused AJV validation to reject create-sales-order requests where customer was provided without createdAt, updatedAt, or tenantId — fields that are server-generated and should never come from the client. Override the customer field to use CustomerSchema.omit({ createdAt, updatedAt, tenantId }), keeping id for customer identification. Co-Authored-By: Claude Opus 4.6 --- server/src/schemas/tool-inputs/create-sales-order.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/server/src/schemas/tool-inputs/create-sales-order.ts b/server/src/schemas/tool-inputs/create-sales-order.ts index 27c0238..7509986 100644 --- a/server/src/schemas/tool-inputs/create-sales-order.ts +++ b/server/src/schemas/tool-inputs/create-sales-order.ts @@ -1,9 +1,14 @@ import { z } from 'zod'; import { Order, OrderSchema } from '../entities/order.js'; +import { Customer, CustomerSchema } from '../entities/customer.js'; import { makeZodFieldMap } from '../utils/schema-util.js'; const immutableOrderFields = ['id', 'createdAt', 'updatedAt', 'tenantId'] as const satisfies (keyof Order)[]; +const serverOnlyCustomerFields = ['createdAt', 'updatedAt', 'tenantId'] as const satisfies (keyof Customer)[]; + export const CreateSalesOrderInputSchema = z.object({ - order: OrderSchema.omit(makeZodFieldMap(immutableOrderFields)), + order: OrderSchema.omit(makeZodFieldMap(immutableOrderFields)).extend({ + customer: CustomerSchema.omit(makeZodFieldMap(serverOnlyCustomerFields)).optional(), + }), }); export type CreateSalesOrderInput = z.infer; From 96af66a74413c8e00a7243e5338f2794af36bd17 Mon Sep 17 00:00:00 2001 From: Basil Kotov Date: Mon, 23 Mar 2026 08:42:49 +0000 Subject: [PATCH 2/2] test: remove server-generated fields from customer fixtures in integration tests --- server/tests/integration/adapter.test.ts | 16 +++++----------- server/tests/integration/e2e-workflows.test.ts | 16 +++++----------- server/tests/integration/tools.test.ts | 16 +++++----------- 3 files changed, 15 insertions(+), 33 deletions(-) diff --git a/server/tests/integration/adapter.test.ts b/server/tests/integration/adapter.test.ts index 655c0e5..580b730 100644 --- a/server/tests/integration/adapter.test.ts +++ b/server/tests/integration/adapter.test.ts @@ -11,17 +11,11 @@ const baseAddress = (overrides: Partial> = {}) => ({ ...overrides, }); -const buildCustomer = (extId: string) => { - const timestamp = new Date().toISOString(); - return { - id: `CUST-${extId}-${Date.now()}`, - tenantId: 'mock-tenant', - createdAt: timestamp, - updatedAt: timestamp, - email: `${extId.toLowerCase()}@example.com`, - firstName: 'Adapter', - }; -}; +const buildCustomer = (extId: string) => ({ + id: `CUST-${extId}-${Date.now()}`, + email: `${extId.toLowerCase()}@example.com`, + firstName: 'Adapter', +}); const buildOrder = (extId: string) => ({ externalId: extId, diff --git a/server/tests/integration/e2e-workflows.test.ts b/server/tests/integration/e2e-workflows.test.ts index 642c79d..a0bd5ea 100644 --- a/server/tests/integration/e2e-workflows.test.ts +++ b/server/tests/integration/e2e-workflows.test.ts @@ -11,17 +11,11 @@ const address = (overrides: Partial> = {}) => ({ ...overrides, }); -const buildCustomer = (prefix: string) => { - const timestamp = new Date().toISOString(); - return { - id: `WF-CUST-${prefix}-${Date.now()}`, - tenantId: 'mock-tenant', - createdAt: timestamp, - updatedAt: timestamp, - email: `${prefix.toLowerCase()}@example.com`, - firstName: prefix, - }; -}; +const buildCustomer = (prefix: string) => ({ + id: `WF-CUST-${prefix}-${Date.now()}`, + email: `${prefix.toLowerCase()}@example.com`, + firstName: prefix, +}); const buildOrderPayload = (prefix: string) => ({ externalId: `${prefix}-${Date.now()}`, diff --git a/server/tests/integration/tools.test.ts b/server/tests/integration/tools.test.ts index ae07909..82a83d7 100644 --- a/server/tests/integration/tools.test.ts +++ b/server/tests/integration/tools.test.ts @@ -11,17 +11,11 @@ const requiredAddress = (overrides: Partial> = {}) => ({ ...overrides, }); -const buildCustomer = (prefix: string) => { - const timestamp = new Date().toISOString(); - return { - id: `CUST-${prefix}-${Date.now()}`, - tenantId: 'mock-tenant', - createdAt: timestamp, - updatedAt: timestamp, - email: `${prefix.toLowerCase()}@example.com`, - firstName: prefix, - }; -}; +const buildCustomer = (prefix: string) => ({ + id: `CUST-${prefix}-${Date.now()}`, + email: `${prefix.toLowerCase()}@example.com`, + firstName: prefix, +}); const makeLineItem = (idSuffix: string) => ({ id: `LI-${idSuffix}`,