Skip to content

Commit 7f32a2d

Browse files
dougborgclaude
andcommitted
feat(client)!: 2026-05-14 spec drift sweep + CVE bumps
Combined output of: 1. ``poe refresh-upstream-spec`` — fresh live-gateway OAS + README.io portal spec. 2. Manual prose-drift audit (5 parallel sub-agents across all API areas) comparing per-object README.io reference pages against the local spec. The reference markdown corpus those agents read lives in PR #743; this PR focuses on the spec edits that came out of the audit. 3. Live-API verification for fields that can't be confirmed from docs alone. ## Spec changes ### New schema fields (additive) - ``Variant.abc_classification`` (enum ``A`` / ``B`` / ``C``, nullable). New shared ``AbcClassification`` enum schema. - ``SalesOrderRow.serial_number_transactions`` (array of ``{serial_number_id, quantity: 0|1}`` — Katana's audit trail of serial-number add/remove actions). - ``UpdateManufacturingOrderOperationRowRequest.manufacturing_order_id`` property added; ``manufacturing_order_id`` + ``status`` now required. - ``UpdateProductRequest.configs.items.id`` optional integer (lets callers rename a config by id instead of matching by name). ### Wire-format types: ``number`` → ``string`` on read schemas Katana returns fixed-precision decimals as strings on the wire (``"0.0300000000"``). Our generated client previously typed these as ``float``, which the pydantic client silently coerced (lossy precision) and the attrs client passed through as ``str`` while claiming ``float`` (runtime type lie). The read schemas now match what the wire delivers: - ``SalesOrderRow.price_per_unit``, ``cogs_value`` - ``ManufacturingOrderRecipeRow.planned_quantity_per_unit`` - ``ManufacturingOrderOperationRow.planned_time_per_unit``, ``planned_time_parameter``, ``total_actual_time``, ``planned_cost_per_unit``, ``total_actual_cost`` Write-side DTOs (``Create*Request``, ``Update*Request``) keep ``number`` — the API accepts numeric input on write. ### Removed schemas / new endpoints - ``SalesOrderSearchRequest`` and ``SalesOrderSearchRequestFilter`` removed; ``POST /sales_orders/search`` now references the consolidated ``SearchFilterRequest``. - New endpoint ``POST /sales_order_rows/search`` — LoopBack-style filter envelope, returns ``SalesOrderRowListResponse``. Response shape verified against live API (issue #733 closed). - New ``SearchFilterRequest`` schema (shared by both search endpoints). ### Relaxed-required + renames - ``CreatePurchaseOrderRequest.order_no`` and ``CreateSalesOrderRequest.order_no`` no longer required — Katana auto-generates a sequential PO/SO number when omitted. - ``CreateSalesOrderRowRequest.attributes.items.name`` → ``key`` (renamed to match the read schema's ``SalesOrderRowAttribute``). Same change on ``UpdateSalesOrderRowRequest``. ### Other field-level corrections - ``CreateVariantRequest.registered_barcode`` — removed ``minLength: 3``, widened ``maxLength`` 40 → 120 to match Update + upstream. - ``CreateSerialNumbersRequest`` — ``resource_type`` and ``serial_numbers`` added to ``required``. - ``CreateStockTransferRequest.stock_transfer_number`` + ``CreateStockAdjustmentRequest.stock_adjustment_number`` — added ``minLength: 1``. - ``Inventory.safety_stock_level`` — added to ``required`` (live API always populates the field). - ``DemandForecastPeriod.in_stock`` description fixed: "at the start" → "at the end of the period". - ``PurchaseOrderRow.price_per_unit`` description copy-paste typo fixed ("sales price… in sales order currency" → "purchase price… in purchase order currency"). - ``Webhook.subscribed_events.items`` now ``$ref``'s the ``WebhookEvent`` enum (previously a free-form string); stale example event names removed. - ``CreateSalesOrderFulfillmentRequest.tracking_number`` / ``tracking_url`` — added missing ``maxLength`` constraints (256 / 2048). - Deprecation markers added to ``cost_per_hour`` / ``planned_time_per_unit`` across ``ManufacturingOrderOperationRow``, its Create / Update siblings, and ``ProductOperationRow`` (upstream documents these as superseded by ``cost_parameter`` / ``planned_time_parameter``). ## Supporting changes - ``scripts/generate_pydantic_models.py`` — ``serial_number_transactions`` added to ``SalesOrderRow``'s ``json_columns`` so the cached SQLModel serializes it via ``PydanticJSON``. - ``katana_mcp_server/src/katana_mcp/tools/tool_result_utils.py`` — new ``float_or_none`` helper for coercing wire-format decimal strings at the domain boundary. - ``katana_mcp_server/src/katana_mcp/tools/foundation/sales_orders.py`` — ``SalesOrderRowInfo`` / ``SalesOrderRowDetail`` mappings now route ``price_per_unit`` / ``cogs_value`` through ``float_or_none`` so the consumer-facing models stay numeric. - Test factories (``katana_mcp_server/tests/factories.py``) accept ``float | str | None`` and stringify internally for caller convenience. ## CVE bumps Pre-existing transitive vulnerabilities flagged by Trivy when this PR's ``uv.lock`` changes made them appear in the diff. Bumping in-place to the fixed versions: - ``gitpython`` 3.1.46 → 3.1.50 (CVE-2026-42215, -42284, -44243, -44244, GHSA-mv93-w799-cj2w). Transitive via ``python-semantic-release``. - ``python-multipart`` 0.0.24 → 0.0.28 (CVE-2026-42561). Transitive via the MCP tooling chain. - ``cryptography`` 46.0.6 → 48.0.0 (CVE-2026-39892). Transitive via ``pyjwt[crypto]``. ## Deferred work Tier 2 findings from the audit that require live-API verification before applying are tracked separately as #736 (items), #737 (customers/custom fields/webhooks), #738 (inventory/stock), #739 (sales). The unverified money-fields wire-format sweep continues in #735. BREAKING CHANGE: Multiple field types narrowed from ``number`` to ``string`` on read schemas (``SalesOrderRow.price_per_unit`` / ``cogs_value``, ``ManufacturingOrderRecipeRow.planned_quantity_per_unit``, ``ManufacturingOrderOperationRow.planned_time_per_unit`` / ``planned_time_parameter`` / ``total_actual_time`` / ``planned_cost_per_unit`` / ``total_actual_cost``). Consumers doing arithmetic on these need to parse them (e.g., ``float(row.price_per_unit)`` or ``decimal.Decimal(row.price_per_unit)``); pydantic clients in lax mode will continue to auto-coerce. The ``SalesOrderSearchRequest`` / ``SalesOrderSearchRequestFilter`` classes are removed — callers of ``POST /sales_orders/search`` should switch to ``SearchFilterRequest``. ``SalesOrderRow``'s ``attributes.items`` request field is renamed ``name`` → ``key`` on Create / Update DTOs (matches the read shape). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent f93c838 commit 7f32a2d

49 files changed

Lines changed: 2296 additions & 432 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

docs/katana-openapi.yaml

Lines changed: 254 additions & 89 deletions
Large diffs are not rendered by default.

docs/upstream-specs/live-gateway.yaml

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1049,7 +1049,6 @@ components:
10491049
maximum: 2147483647
10501050
type: integer
10511051
required:
1052-
- order_no
10531052
- supplier_id
10541053
- location_id
10551054
- purchase_order_rows
@@ -1284,6 +1283,10 @@ components:
12841283
type: object
12851284
nullable: false
12861285
type: array
1286+
custom_fields:
1287+
additionalProperties: true
1288+
nullable: true
1289+
type: object
12871290
location_id:
12881291
maximum: 2147483647
12891292
minimum: 1
@@ -1338,7 +1341,6 @@ components:
13381341
nullable: true
13391342
type: string
13401343
required:
1341-
- order_no
13421344
- customer_id
13431345
- sales_order_rows
13441346
title: CreateSalesOrderDto
@@ -1455,6 +1457,10 @@ components:
14551457
type: object
14561458
nullable: false
14571459
type: array
1460+
custom_fields:
1461+
additionalProperties: true
1462+
nullable: true
1463+
type: object
14581464
location_id:
14591465
maximum: 2147483647
14601466
minimum: 1
@@ -3572,6 +3578,10 @@ components:
35723578
type: object
35733579
nullable: false
35743580
type: array
3581+
custom_fields:
3582+
additionalProperties: true
3583+
nullable: true
3584+
type: object
35753585
location_id:
35763586
maximum: 2147483647
35773587
minimum: 1
@@ -7708,6 +7718,22 @@ paths:
77087718
- SalesOrderRowController
77097719
x-controller-name: SalesOrderRowController
77107720
x-operation-name: createSalesOrderRow
7721+
/sales_order_rows/search:
7722+
post:
7723+
operationId: SalesOrderRowController.searchSalesOrderRows
7724+
requestBody:
7725+
content:
7726+
application/json:
7727+
schema:
7728+
$ref: '#/components/schemas/SearchFilterDto'
7729+
required: true
7730+
responses:
7731+
'200':
7732+
description: Return value of SalesOrderRowController.searchSalesOrderRows
7733+
tags:
7734+
- SalesOrderRowController
7735+
x-controller-name: SalesOrderRowController
7736+
x-operation-name: searchSalesOrderRows
77117737
/sales_order_rows/{id}:
77127738
delete:
77137739
operationId: SalesOrderRowController.deleteSalesOrderRow

0 commit comments

Comments
 (0)