Skip to content

PROD-1492: only halt on duplicate model mappings when a source ID is still live#194

Merged
jules-exel merged 3 commits into
mainfrom
PROD-1492/scope-dup-mapping-gate-to-live-models
Jul 23, 2026
Merged

PROD-1492: only halt on duplicate model mappings when a source ID is still live#194
jules-exel merged 3 commits into
mainfrom
PROD-1492/scope-dup-mapping-gate-to-live-models

Conversation

@jules-exel

@jules-exel jules-exel commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Summary

Follow-up to #191 (merged). That PR added a pre-push gate in pushModels that halts the sync when the mapping file contains two records sharing a source referenceName — the PROD-1492 "deleted-and-recreated model" corruption. But the gate fired on any such duplicate, including a model that was deleted outright (both records point at source models that no longer exist), which is a false positive that blocks the entire sync over stale mapping residue.

Real example from a 63b1dc5d-us2 → 95bfb840-us2 sync: a case-only ChangeLog (source 110 → target 18) / Changelog (source 117 → target 24) pair where both source models are gone from the pull. Nothing references them, no content of that type is in the push — yet the sync hard-stopped.

Change

Scope the gate to duplicates where at least one conflicting source ID is still live in the current pull:

  • Live-vs-dead (the PROD-1492 case, e.g. PromoBanner 46-dead / 48-live) → still throws Model validation failed and halts. ✅ ticket behavior preserved.
  • Fully-dead (e.g. ChangeLog/Changelog, both absent) → silently ignored, sync continues. ✅ no false halt.

getDuplicateSourceReferenceNames (case-insensitive) is unchanged; the LeftSidebar/template validation halt from #191 is untouched.

Tests

model-pusher.test.ts:

  • live-vs-dead duplicate → throws Model validation failed, writes nothing.
  • fully-dead duplicate → resolves success, no halt.

All model / mapper / orchestrate suites pass; tsc clean.

Sync before:
image

Sync after by-passed deleted models with same name

jules-exel and others added 3 commits July 22, 2026 16:23
Two related fixes so a mapping-inconsistency guard actually stops the
sync instead of being swallowed and silently continuing.

1. Template validation was swallowed. The guid-level orchestrator only
   re-threw errors containing "Model validation failed", but the template
   guard throws "Page template validation failed" — so it fell through to
   a yellow warning and the sync kept going. Broaden the re-throw match to
   any "validation failed" so template (and future) guards hard-stop.

2. Duplicate model reference-name was undetected. When a source model is
   deleted and recreated (new ID, same referenceName), the mapping keeps
   two records sharing that name — one pointing at the dead source model.
   The content-side lookup is first-match-wins, so it can latch onto the
   dead record and SILENTLY skip that model's content, after which pages
   referencing it fail with "No content mapping". The ID-based rename guard
   misses this (different source IDs = duplicate name, not duplicate ID).
   Add ModelMapper.getDuplicateSourceReferenceNames() and a pre-push
   integrity gate in pushModels that throws "Model validation failed:
   duplicate model mapping ..." before any writes.

Tests: new orchestrate-pushers test (template failure aborts before
content/pages) and new model-pusher test (duplicate-name mapping throws
and writes nothing). Added per-test mapping-file cleanup so seeded
mappings no longer leak between model-pusher tests.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…still live

The duplicate-reference-name gate added in #191 halted the sync on ANY
mapping that had two records sharing a source referenceName. That over-fires
on a model deleted OUTRIGHT: both records point at source models that no
longer exist (e.g. the case-only "ChangeLog"/"Changelog" pair, source IDs
110 & 117, both absent from the pull). There is no content of that type in
the push and nothing references it, so halting is a false positive that
blocks the whole sync over stale mapping residue.

Scope the gate to duplicates where at least one conflicting source ID is
still live in the current pull. That preserves the PROD-1492 fix (dead + live
record, e.g. PromoBanner 46-dead / 48-live, still hard-stops the sync) while
ignoring fully-dead residue silently.

Tests: model-pusher.test.ts now covers both the live-vs-dead halt and the
fully-dead no-halt path.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@jules-exel
jules-exel requested a review from 5PK July 23, 2026 19:40
@jules-exel
jules-exel merged commit c31e50c into main Jul 23, 2026
3 checks passed
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.

2 participants