Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .squad/decisions.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

## Active Decisions

### 2026-06-05T23:40:00Z: Operation reconciliation PATCH strips schema refs
**By:** ApimExpert + TypeScriptDev
**Status:** Implemented
**What:** `reconcileOperationsAfterSpecImport` removes `schemaId` and `typeName` from operation `request.representations` and `responses[].representations` before PATCH.
**Why:** Those IDs are source-instance specific. After target spec import, APIM assigns its own schema IDs; sending stale source IDs causes APIM to drop schema refs.

### 2026-05-28T23:06:01Z: Team-Wide Evidence Standard
**By:** User directive (anonymized)
**Status:** Active directive
Expand Down
36 changes: 36 additions & 0 deletions src/services/api-publisher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,9 @@ async function reconcileOperationsAfterSpecImport(
}
}

// Strip source schema refs; APIM rebinds on import and drops stale IDs.
stripRepresentationSchemaRefs(patchProps);

if (Object.keys(patchProps).length === 0) return;

const patchBody: Record<string, unknown> = { properties: patchProps };
Expand All @@ -456,6 +459,39 @@ async function reconcileOperationsAfterSpecImport(
}
}

/** Strip source schema refs from request/response representations before PATCH. */
function stripRepresentationSchemaRefs(patchProps: Record<string, unknown>): void {
const SCHEMA_REF_FIELDS = ['schemaId', 'typeName'];

function stripFromRepresentations(representations: unknown): void {
if (!Array.isArray(representations)) return;
for (const rep of representations) {
if (rep && typeof rep === 'object') {
for (const field of SCHEMA_REF_FIELDS) {
delete (rep as Record<string, unknown>)[field];
}
}
}
}

// Strip schema refs from request.representations.
const request = patchProps.request;
if (request && typeof request === 'object') {
const req = request as Record<string, unknown>;
stripFromRepresentations(req.representations);
}

// Strip schema refs from responses[].representations.
const responses = patchProps.responses;
if (Array.isArray(responses)) {
for (const response of responses) {
if (response && typeof response === 'object') {
stripFromRepresentations((response as Record<string, unknown>).representations);
}
}
}
}

/**
* Extract revision number from API name (e.g., "my-api;rev=2" -> 2)
*/
Expand Down