fix(PROD-2211): robust handling of model "Unable to save the model" failures#167
Merged
Merged
Conversation
…ailures The model pusher mishandled saveModel failures, leaving incomplete mappings and reporting success when models actually failed. Four fixes: 1. Verify-then-map on a failed save (create AND update). saveModel can reject even though the API persisted the model. The catch now re-queries the target by (referenceName, contentDefinitionTypeID); a create is recovered if the model exists, an update if the saved field count matches the source (so a genuine reject like a 404 missing-definition still fails). Recovered saves write the mapping and report success. 2. Report failures honestly. The update loop used `if (result)` where result is the string "updated" | "failed" — "failed" is truthy, so failures were counted as successes with a green banner. Now compares `=== "updated"`. 3. Map-on-adopt. When a model exists on target by reference but has no mapping, the non-default branch now writes the mapping (and skips) instead of silently dropping the model, so re-syncs self-heal. 4. Type-aware lookups, keyed by (referenceName, contentDefinitionTypeID) with a name-only fallback, closing the same-name different-type collision (PROD-1505). Also unwrap the SDK's `innerError` in logger.model.error so the real API status and response body land in the log instead of the generic "Unable to save the model." Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
5PK
approved these changes
Jun 17, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
PROD-2211
The model pusher (
src/lib/pushers/model-pusher.ts) mishandledsaveModelfailures: it left incomplete mappings, silently dropped models, and reported success when models actually failed. TheUnable to save the model.string comes from@agility/management-sdk(which just rethrows any failure generically) — the disambiguation has to happen in the CLI, which is where all of this lands. Neither SDK needed changes.Fixes
1. Verify-then-recover on a failed save (creates and updates).
saveModelcan reject even though the API persisted the model (timeout-with-server-completion, response-parse race). The catch now re-queries the target by(referenceName, contentDefinitionTypeID):Definition for setting X not found, which leaves fields unapplied) correctly stays failed.Recovered saves write the mapping and report success (silently).
2. Report failures honestly.
The update loop used
if (result)whereresultis the string"updated" | "failed"—"failed"is truthy, so failed field-updates were counted as successes and the banner went green. Now compares=== "updated", so failures incrementfailed, surface in the ERROR SUMMARY, and flip the banner.3. Map-on-adopt.
When a model exists on the target by reference but has no mapping row, the non-default branch previously set
targetModeland fell through every condition (all gated onsourceMapping), silently dropping the model. It now writes the mapping and skips, so re-syncs self-heal instead of wedging.4. Type-aware lookups.
Model lookups are keyed by
(referenceName, contentDefinitionTypeID)with a name-only fallback (older pulls/fixtures), closing the same-name different-type collision (e.g. a Content List vs a Module both namedPromoBanner) — the PROD-1505 family.Bonus:
logger.model.errornow unwraps the SDK'sinnerError, so the real API status + response body land in the log file instead of the genericUnable to save the model.(replaces a rawconsole.errordebug block).Tests
6 new cases in
model-pusher.test.ts: failed-update-stays-failed, false-negative create recovery, different-type-same-name stays failed, failed-update recovery on field-count match, map-on-adopt writes the mapping + skips, and type-blind non-adoption. Full suite 1711 passing, typecheck clean.Related
referenceName-only lookup.🤖 Generated with Claude Code